home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 5
/
Aminet 5 - March 1995.iso
/
Aminet
/
game
/
role
/
Ang261Lib.lha
/
src
/
spells.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-10-22
|
138KB
|
5,007 lines
/*
* spells.c: code for player and creature spells, breaths, wands, scrolls,
* etc.
*
* Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
*
* This software may be copied and distributed for educational, research, and
* not for profit purposes provided that this copyright and statement are
* included in all such copies.
*/
#include "constant.h"
#include "config.h"
#include "types.h"
#include "monster.h"
#include "externs.h"
#ifdef USG
#ifndef ATARIST_MWC
#include <string.h>
#endif
#else
#ifndef VMS
#include <strings.h>
#endif
#endif
/* Lets do all prototypes correctly.... -CWS */
#ifndef NO_LINT_ARGS
#ifdef __STDC__
static char bolt_char(int, int, int, int);
static void ball_destroy(int, int (**) ());
static void pause_if_screen_full(int *, int);
static void spell_hit_monster(monster_type *, int, int *, int, int *, int *, int8u);
static void replace_spot(int, int, int);
#else
static char bolt_char();
static void ball_destroy();
static void pause_if_screen_full();
static void spell_hit_monster();
static void replace_spot();
#endif
#endif
/* Following are spell procedure/functions -RAK- */
/* These routines are commonly used in the scroll, potion, wands, and */
/* staves routines, and are occasionally called from other areas. */
/* Now included are creature spells also. -RAK */
/* this assumes only 1 move apart -CFT */
static char
bolt_char(y, x, ny, nx)
int y, x, ny, nx;
{
if (ny == y) return '-';
if (nx == x) return '|';
if ((ny-y) == (nx-x)) return '\\';
return '/';
}
/* return the appropriate item destroy test to the typ. All that's left of
* get_flags(). -CFT
*/
/*
* add new destroys? maybe GF_FORCE destroy potions, GF_PLASMA as lightning,
* GF_SHARDS and GF_ICE maybe break things (potions?), and GF_METEOR breaks
* potions and burns scrolls? not yet, but it's an idea... -CFT
*/
static void
ball_destroy(typ, destroy)
int typ;
int (**destroy) ();
{
switch (typ) {
case GF_FIRE:
*destroy = set_fire_destroy;
break;
case GF_ACID:
*destroy = set_acid_destroy;
break;
case GF_FROST:
case GF_SHARDS:
case GF_ICE:
case GF_FORCE:
case GF_SOUND:
*destroy = set_frost_destroy; /* just potions and flasks -DGK */
break;
case GF_LIGHTNING:
*destroy = set_lightning_destroy;
break;
case GF_PLASMA: /* DGK */
*destroy = set_plasma_destroy; /* fire+lightning -DGK */
break;
case GF_METEOR: /* DGK */
*destroy = set_meteor_destroy; /* fire+shards -DGK */
break;
case GF_MANA: /* DGK */
*destroy = set_mana_destroy; /* everything -DGK */
break;
case GF_HOLY_ORB: /* DGK */
*destroy = set_holy_destroy; /* cursed stuff -DGK */
break;
case GF_MAGIC_MISSILE:
case GF_POISON_GAS:
case GF_ARROW:
case GF_NETHER:
case GF_WATER:
case GF_CHAOS:
case GF_CONFUSION:
case GF_DISENCHANT:
case GF_NEXUS:
case GF_INERTIA:
case GF_LIGHT:
case GF_DARK:
case GF_TIME:
case GF_GRAVITY:
*destroy = set_null;
break;
default:
msg_print("Unknown typ in ball_destroy(). This may mean trouble.");
*destroy = set_null;
break;
}
}
void
monster_name(m_name, m_ptr, r_ptr)
char *m_name;
monster_type *m_ptr;
creature_type *r_ptr;
{
if (!m_ptr->ml)
(void)strcpy(m_name, "It");
else {
if (r_ptr->cdefense & UNIQUE)
(void)sprintf(m_name, "%s", r_ptr->name);
else
(void)sprintf(m_name, "The %s", r_ptr->name);
}
}
void
lower_monster_name(m_name, m_ptr, r_ptr)
char *m_name;
monster_type *m_ptr;
creature_type *r_ptr;
{
if (!m_ptr->ml)
(void)strcpy(m_name, "it");
else {
if (r_ptr->cdefense & UNIQUE)
(void)sprintf(m_name, "%s", r_ptr->name);
else
(void)sprintf(m_name, "the %s", r_ptr->name);
}
}
/* teleport you a level (or three:-) */
void
tele_level()
{
if (dun_level == Q_PLANE)
dun_level = 0;
else if (is_quest(dun_level))
dun_level -= 1;
else
dun_level += (-3) + 2 * randint(2);
if (dun_level < 0)
dun_level = 0;
new_level_flag = TRUE;
}
/* Sleep creatures adjacent to player -RAK- */
int
sleep_monsters1(y, x)
int y, x;
{
register int i, j;
register cave_type *c_ptr;
register monster_type *m_ptr;
register creature_type *r_ptr;
int sleep;
vtype out_val, m_name;
sleep = FALSE;
for (i = y - 1; i <= y + 1; i++)
for (j = x - 1; j <= x + 1; j++) {
c_ptr = &cave[i][j];
if (c_ptr->cptr > 1) {
m_ptr = &m_list[c_ptr->cptr];
r_ptr = &c_list[m_ptr->mptr];
monster_name(m_name, m_ptr, r_ptr);
if ((r_ptr->level >
randint((py.misc.lev - 10) < 1 ? 1 : (py.misc.lev - 10)) + 10) ||
(CHARM_SLEEP & r_ptr->cdefense) || (r_ptr->cdefense & UNIQUE)) {
if (m_ptr->ml && (r_ptr->cdefense & CHARM_SLEEP))
c_recall[m_ptr->mptr].r_cdefense |= CHARM_SLEEP;
(void)sprintf(out_val, "%s is unaffected.", m_name);
msg_print(out_val);
} else {
sleep = TRUE;
m_ptr->csleep = 500;
(void)sprintf(out_val, "%s falls asleep.", m_name);
msg_print(out_val);
}
}
}
return (sleep);
}
int
lose_all_info()
{
int i;
for (i = 0; i <= INVEN_AUX; i++) {
if (inventory[i].tval != TV_NOTHING)
inventory[i].ident &= ~(ID_KNOWN2);
}
wizard_light(-1);
return (0);
}
void
identify_pack()
{
int i;
inven_type *i_ptr;
for (i = 0; i <= INVEN_AUX; i++) {
if (inventory[i].tval != TV_NOTHING)
identify(&i);
i_ptr = &inventory[i];
known2(i_ptr);
}
}
/* Detect any treasure on the current panel -RAK- */
int
detect_treasure()
{
register int i, j, detect;
register cave_type *c_ptr;
detect = FALSE;
for (i = panel_row_min; i <= panel_row_max; i++)
for (j = panel_col_min; j <= panel_col_max; j++) {
c_ptr = &cave[i][j];
if ((c_ptr->tptr != 0) && (t_list[c_ptr->tptr].tval == TV_GOLD) &&
!test_light(i, j)) {
c_ptr->fm = TRUE;
lite_spot(i, j);
detect = TRUE;
}
}
return (detect);
}
/* This will light up all spaces with "magic" items, including potions,
* scrolls, rods, wands, staves, amulets, rings, and "enchanted" items. This
* excludes all foods and spell books. -- JND
*/
int
detect_magic()
{
register int i, j, detect;
register cave_type *c_ptr;
register inven_type *t_ptr;
int Tval;
detect = FALSE;
for (i = panel_row_min; i <= panel_row_max; i++)
for (j = panel_col_min; j <= panel_col_max; j++) {
c_ptr = &cave[i][j];
if ((c_ptr->tptr != 0) && (t_list[c_ptr->tptr].tval < TV_MAX_OBJECT)
&& !test_light(i, j)) {
t_ptr = &t_list[c_ptr->tptr];
Tval = t_ptr->tval;
/* Is it a weapon or armor or light? */
if (((Tval > 9) && (Tval < 39)) &&
(((t_ptr->tohit > 0) || (t_ptr->todam) || (t_ptr->toac)
/* If so, check for plusses on weapons and armor ... */
|| (t_ptr->flags2 & TR_ARTIFACT))
/* ... and check whether it is an artifact! ;) */
|| ((Tval > 39) && (Tval < 77)))){ /* Is it otherwise magical? */
c_ptr->fm = TRUE;
lite_spot(i, j);
detect = TRUE;
}
}
}
return (detect);
}
int
detect_enchantment()
{
register int i, j, detect, tv;
register cave_type *c_ptr;
detect = FALSE;
for (i = panel_row_min; i <= panel_row_max; i++)
for (j = panel_col_min; j <= panel_col_max; j++) {
c_ptr = &cave[i][j];
tv = t_list[c_ptr->tptr].tval;
if ((c_ptr->tptr != 0) && !test_light(i, j) &&
( ((tv > TV_MAX_ENCHANT) && (tv < TV_FLASK)) || /* misc items */
(tv == TV_MAGIC_BOOK) || (tv == TV_PRAYER_BOOK) || /* books */
((tv >= TV_MIN_WEAR) && (tv <= TV_MAX_ENCHANT) && /* armor/weap */
((t_list[c_ptr->tptr].flags2 & TR_ARTIFACT) || /* if Art., or */
(t_list[c_ptr->tptr].tohit>0) || /* has pluses, then show */
(t_list[c_ptr->tptr].todam>0) ||
(t_list[c_ptr->tptr].toac>0))) )){
c_ptr->fm = TRUE;
lite_spot(i, j);
detect = TRUE;
}
}
return(detect);
}
int
detection()
{
register int i, detect;
register monster_type *m_ptr;
detect_treasure();
detect_object();
detect_trap();
detect_sdoor();
detect = FALSE;
for (i = mfptr - 1; i >= MIN_MONIX; i--) {
m_ptr = &m_list[i];
if (panel_contains((int)m_ptr->fy, (int)m_ptr->fx)) {
m_ptr->ml = TRUE;
/* works correctly even if hallucinating */
print((char)c_list[m_ptr->mptr].cchar, (int)m_ptr->fy,
(int)m_ptr->fx);
detect = TRUE;
}
}
if (detect) {
msg_print("You sense the presence of monsters!");
msg_print(NULL);
/* must unlight every monster just lighted */
creatures(FALSE);
}
return (detect);
}
/* Detect all objects on the current panel -RAK- */
int
detect_object()
{
register int i, j, detect;
register cave_type *c_ptr;
detect = FALSE;
for (i = panel_row_min; i <= panel_row_max; i++)
for (j = panel_col_min; j <= panel_col_max; j++) {
c_ptr = &cave[i][j];
if ((c_ptr->tptr != 0) && (t_list[c_ptr->tptr].tval < TV_MAX_OBJECT)
&& !test_light(i, j)) {
c_ptr->fm = TRUE;
lite_spot(i, j);
detect = TRUE;
}
}
return (detect);
}
/* Locates and displays traps on current panel -RAK- */
int
detect_trap()
{
register int i, j;
int detect;
register cave_type *c_ptr;
register inven_type *t_ptr;
detect = FALSE;
for (i = panel_row_min; i <= panel_row_max; i++)
for (j = panel_col_min; j <= panel_col_max; j++) {
c_ptr = &cave[i][j];
if (c_ptr->tptr != 0)
if (t_list[c_ptr->tptr].tval == TV_INVIS_TRAP) {
c_ptr->fm = TRUE;
change_trap(i, j);
detect = TRUE;
} else if (t_list[c_ptr->tptr].tval == TV_CHEST) {
t_ptr = &t_list[c_ptr->tptr];
known2(t_ptr);
}
}
return (detect);
}
void
stair_creation()
{
register cave_type *c_ptr;
register int cur_pos;
c_ptr = &cave[char_row][char_col];
if ((c_ptr->tptr == 0) ||
((t_list[c_ptr->tptr].tval != TV_UP_STAIR) /* if not stairs or a store */
&& (t_list[c_ptr->tptr].tval != TV_DOWN_STAIR)
&& (t_list[c_ptr->tptr].tval != TV_STORE_DOOR)
&& ((t_list[c_ptr->tptr].tval < TV_MIN_WEAR) ||
(t_list[c_ptr->tptr].tval > TV_MAX_WEAR) ||
!(t_list[c_ptr->tptr].flags2 & TR_ARTIFACT)))) {
/* if no artifact here -CFT */
if (c_ptr->tptr != 0)
(void)delete_object(char_row, char_col);
cur_pos = popt();
c_ptr->tptr = cur_pos;
if ((randint(2) == 1 || is_quest(dun_level)) && (dun_level > 0))
invcopy(&t_list[cur_pos], OBJ_UP_STAIR);
else
invcopy(&t_list[cur_pos], OBJ_DOWN_STAIR);
} else
msg_print("The object resists the spell.");
}
/* Surround the player with doors. -RAK- */
int
door_creation()
{
register int i, j, door;
int k;
register cave_type *c_ptr;
door = FALSE;
for (i = char_row - 1; i <= char_row + 1; i++)
for (j = char_col - 1; j <= char_col + 1; j++)
if ((i != char_row) || (j != char_col)) {
c_ptr = &cave[i][j];
if (c_ptr->fval <= MAX_CAVE_FLOOR) {
if ((c_ptr->tptr == 0) ||
((t_list[c_ptr->tptr].tval != TV_UP_STAIR)
/* if not stairs or a store */
&&(t_list[c_ptr->tptr].tval != TV_DOWN_STAIR)
&& (t_list[c_ptr->tptr].tval != TV_STORE_DOOR)) ||
(t_list[c_ptr->tptr].tval < TV_MIN_WEAR) ||
(t_list[c_ptr->tptr].tval > TV_MAX_WEAR) ||
!(t_list[c_ptr->tptr].flags2 & TR_ARTIFACT)) {
/* if no artifact here -CFT */
door = TRUE;
if (c_ptr->tptr != 0)
(void)delete_object(i, j);
k = popt();
c_ptr->fval = BLOCKED_FLOOR;
c_ptr->tptr = k;
invcopy(&t_list[k], OBJ_CLOSED_DOOR);
lite_spot(i, j);
} else
msg_print("The object resists the spell.");
}
}
return (door);
}
/* Locates and displays all secret doors on current panel -RAK- */
int
detect_sdoor()
{
register int i, j, detect;
register cave_type *c_ptr;
detect = FALSE;
for (i = panel_row_min; i <= panel_row_max; i++)
for (j = panel_col_min; j <= panel_col_max; j++) {
c_ptr = &cave[i][j];
if (c_ptr->tptr != 0)
/* Secret doors */
if (t_list[c_ptr->tptr].tval == TV_SECRET_DOOR) {
c_ptr->fm = TRUE;
change_trap(i, j);
detect = TRUE;
}
/* Staircases */
else if (((t_list[c_ptr->tptr].tval == TV_UP_STAIR) ||
(t_list[c_ptr->tptr].tval == TV_DOWN_STAIR)) &&
!c_ptr->fm) {
c_ptr->fm = TRUE;
lite_spot(i, j);
detect = TRUE;
}
}
return (detect);
}
/* Locates and displays all invisible creatures on current panel -RAK- */
int
detect_invisible()
{
register int i, flag;
register monster_type *m_ptr;
flag = FALSE;
for (i = mfptr - 1; i >= MIN_MONIX; i--) {
m_ptr = &m_list[i];
if (panel_contains((int)m_ptr->fy, (int)m_ptr->fx) &&
(CM_INVISIBLE & c_list[m_ptr->mptr].cmove)) {
m_ptr->ml = TRUE;
/* works correctly even if hallucinating */
print((char)c_list[m_ptr->mptr].cchar, (int)m_ptr->fy,
(int)m_ptr->fx);
flag = TRUE;
}
}
if (flag) {
msg_print("You sense the presence of invisible creatures!");
msg_print(NULL);
/* must unlight every monster just lighted */
creatures(FALSE);
}
return (flag);
}
/* Split out of light_line. -DGK */
void
mon_light_dam(y, x, dam)
int y, x, dam;
{
register cave_type *c_ptr;
register monster_type *m_ptr;
register creature_type *r_ptr;
vtype out_val, m_name;
int i;
c_ptr = &cave[y][x];
if (c_ptr->cptr > 1) {
m_ptr = &m_list[c_ptr->cptr];
r_ptr = &c_list[m_ptr->mptr];
monster_name(m_name, m_ptr, r_ptr);
m_ptr->csleep = 0;
if (HURT_LIGHT & r_ptr->cdefense) {
if (m_ptr->ml)
c_recall[m_ptr->mptr].r_cdefense |= HURT_LIGHT;
i = mon_take_hit((int)c_ptr->cptr, dam, FALSE);
if (i >= 0) {
(void)sprintf(out_val, "%s shrivels away in the light!", m_name);
msg_print(out_val);
prt_experience();
} else {
(void)sprintf(out_val, "%s cringes from the light!", m_name);
msg_print(out_val);
}
}
}
}
int
light_area(y, x, dam, rad) /* Expanded -DGK */
register int y, x, dam, rad;
{
register int i, j;
int min_i, max_i, min_j, max_j;
if (rad < 1) rad = 1; /* sanity check -CWS */
if (py.flags.blind < 1)
msg_print("You are surrounded by a white light.");
if ((cave[y][x].fval == LIGHT_FLOOR) && (panel_contains(y, x)))
light_room(y, x);
if (cave[y][x].lr && (dun_level > 0) && !(cave[y][x].pl))
light_room(y, x); /* dbd - fix lighting radius */
/* replace a check for in_bounds2 every loop with 4 quick computations -CWS */
min_i = MY_MAX(0, (y - rad));
max_i = MY_MIN(cur_height - 1, (y + rad));
min_j = MY_MAX(0, (x - rad));
max_j = MY_MIN(cur_width - 1, (x + rad));
for (i = min_i; i <= max_i; i++)
for (j = min_j; j <= max_j; j++)
if (los(y, x, i, j) && (distance(y, x, i, j) <= rad)) {
if (cave[i][j].lr && (dun_level > 0))
light_room(i, j);
cave[i][j].pl = TRUE;
lite_spot(i, j);
if (dam)
mon_light_dam(i, j, dam / (rad == 0 ? 1 : rad));
}
return (TRUE);
}
/* Darken an area, opposite of light area -RAK- */
int
unlight_area(y, x)
int y, x;
{
register int i, j, unlight;
register cave_type *c_ptr;
int min_i, max_i, min_j, max_j;
unlight = FALSE;
if (cave[y][x].lr && (dun_level > 0)) {
darken_room(y, x);
unlight = TRUE;
/* this isn't really good, as it returns true, even if rm was already dark, but
* at least scrolls of darkness will be IDed when used -CFT
*/
} else {
min_i = MY_MAX(0, (y - 3));
max_i = MY_MIN(cur_height - 1, (y + 3));
min_j = MY_MAX(0, (x - 3));
max_j = MY_MIN(cur_width - 1, (x + 3));
/* replace a check for in_bounds2 every loop with 4 quick computations -CWS */
for (i = min_i; i <= max_i; i++)
for (j = min_j; j <= max_j; j++) {
c_ptr = &cave[i][j];
if ((c_ptr->fval == CORR_FLOOR) && (c_ptr->pl || c_ptr->lr)) {
/* pl could have been set by star-lite wand, etc */
c_ptr->pl = FALSE;
c_ptr->tl = FALSE;
unlight = TRUE;
}
}
}
if (unlight && py.flags.blind <= 0)
msg_print("Darkness surrounds you.");
return (unlight);
}
/* Map the current area plus some -RAK- */
void
map_area()
{
register cave_type *c_ptr;
register int i7, i8, n, m;
int i, j, k, l;
i = panel_row_min - randint(10);
j = panel_row_max + randint(10);
k = panel_col_min - randint(20);
l = panel_col_max + randint(20);
for (m = i; m <= j; m++)
for (n = k; n <= l; n++)
if (in_bounds(m, n) && (cave[m][n].fval <= MAX_CAVE_FLOOR))
for (i7 = m - 1; i7 <= m + 1; i7++)
for (i8 = n - 1; i8 <= n + 1; i8++) {
c_ptr = &cave[i7][i8];
if (c_ptr->fval >= MIN_CAVE_WALL)
c_ptr->pl = TRUE;
else if ((c_ptr->tptr != 0) &&
(t_list[c_ptr->tptr].tval >= TV_MIN_VISIBLE) &&
(t_list[c_ptr->tptr].tval <= TV_MAX_VISIBLE))
c_ptr->fm = TRUE;
}
prt_map();
}
/* Identify an object -RAK- */
int
ident_spell()
{
int item_val;
bigvtype out_val, tmp_str;
register int ident;
register inven_type *i_ptr;
ident = FALSE;
switch (get_item(&item_val, "Item you wish identified?", 0,
INVEN_ARRAY_SIZE, 0))
{
case TRUE:
ident = TRUE;
identify(&item_val);
i_ptr = &inventory[item_val];
known2(i_ptr);
objdes(tmp_str, i_ptr, TRUE);
if (item_val >= INVEN_WIELD) {
calc_bonuses();
(void)sprintf(out_val, "%s: %s. ",
describe_use(item_val), tmp_str);
} else
(void)sprintf(out_val, "(%c) %s. ", item_val + 97, tmp_str);
msg_print(out_val);
break;
case FUZZY:
ident = TRUE;
i_ptr = &t_list[cave[char_row][char_col].tptr];
/* that piece of code taken from desc.c:identify()
* no use to convert type for calling identify since obj
* on floor can't stack
*/
if ((i_ptr->flags & TR_CURSED) && (i_ptr->tval != TV_MAGIC_BOOK) &&
(i_ptr->tval != TV_PRAYER_BOOK))
add_inscribe(i_ptr, ID_DAMD);
if (!known1_p(i_ptr))
known1(i_ptr);
/* end of identify-code */
known2(i_ptr);
objdes(tmp_str, i_ptr, TRUE);
(void) sprintf(out_val, "%c %s", item_val+97, tmp_str);
msg_print(out_val+2);
break;
default:
break;
}
return (ident);
}
/* Get all the monsters on the level pissed off. -RAK- */
int
aggravate_monster(dis_affect)
int dis_affect;
{
register int i, aggravate;
register monster_type *m_ptr;
aggravate = FALSE;
for (i = mfptr - 1; i >= MIN_MONIX; i--) {
m_ptr = &m_list[i];
m_ptr->csleep = 0;
if ((m_ptr->cdis <= dis_affect) && (m_ptr->cspeed < 2)) {
m_ptr->cspeed++;
aggravate = TRUE;
}
}
if (aggravate)
msg_print("You hear a sudden stirring in the distance!");
return (aggravate);
}
/* Surround the fool with traps (chuckle) -RAK- */
int
trap_creation()
{
register int i, j, trap;
register cave_type *c_ptr;
trap = FALSE;
for (i = char_row - 1; i <= char_row + 1; i++)
for (j = char_col - 1; j <= char_col + 1; j++) {
if ((i == char_row) && (j == char_col))
continue; /* no trap under player, from um55 -CFT */
c_ptr = &cave[i][j];
if (c_ptr->fval <= MAX_CAVE_FLOOR) {
if ((c_ptr->tptr == 0) ||
((t_list[c_ptr->tptr].tval != TV_UP_STAIR)
/* if not stairs or a store */
&&(t_list[c_ptr->tptr].tval != TV_DOWN_STAIR)
&& (t_list[c_ptr->tptr].tval != TV_STORE_DOOR)) ||
(t_list[c_ptr->tptr].tval < TV_MIN_WEAR) ||
(t_list[c_ptr->tptr].tval > TV_MAX_WEAR) ||
!(t_list[c_ptr->tptr].flags2 & TR_ARTIFACT)) {
/* if no artifact here -CFT */
trap = TRUE;
if (c_ptr->tptr != 0)
(void)delete_object(i, j);
place_trap(i, j, randint(MAX_TRAP) - 1);
/* don't let player gain exp from the newly created traps */
t_list[c_ptr->tptr].p1 = 0;
/* open pits are immediately visible, so call lite_spot */
lite_spot(i, j);
} else
msg_print("The object resists the spell.");
}
}
return (trap);
}
/* Destroys any adjacent door(s)/trap(s) -RAK- */
int
td_destroy()
{
register int i, j, destroy;
register cave_type *c_ptr;
destroy = FALSE;
for (i = char_row - 1; i <= char_row + 1; i++)
for (j = char_col - 1; j <= char_col + 1; j++) {
c_ptr = &cave[i][j];
if (c_ptr->tptr != 0) {
if (((t_list[c_ptr->tptr].tval >= TV_INVIS_TRAP) &&
(t_list[c_ptr->tptr].tval <= TV_CLOSED_DOOR) &&
(t_list[c_ptr->tptr].tval != TV_RUBBLE)) ||
(t_list[c_ptr->tptr].tval == TV_SECRET_DOOR)) {
if (delete_object(i, j))
destroy = TRUE;
} else if (t_list[c_ptr->tptr].tval == TV_CHEST) {
/* destroy traps on chest and unlock */
t_list[c_ptr->tptr].flags &= ~(CH_TRAPPED | CH_LOCKED);
t_list[c_ptr->tptr].name2 = SN_DISARMED;
msg_print("You have disarmed the chest.");
known2(&t_list[c_ptr->tptr]);
destroy = TRUE;
}
}
}
return (destroy);
}
/* Display all creatures on the current panel -RAK- */
int
detect_monsters()
{
register int i, detect;
register monster_type *m_ptr;
detect = FALSE;
for (i = mfptr - 1; i >= MIN_MONIX; i--) {
m_ptr = &m_list[i];
if (panel_contains((int)m_ptr->fy, (int)m_ptr->fx) &&
((CM_INVISIBLE & c_list[m_ptr->mptr].cmove) == 0)) {
m_ptr->ml = TRUE;
/* works correctly even if hallucinating */
print((char)c_list[m_ptr->mptr].cchar, (int)m_ptr->fy,
(int)m_ptr->fx);
detect = TRUE;
}
}
if (detect) {
msg_print("You sense the presence of monsters!");
msg_print(NULL);
/* must unlight every monster just lighted */
creatures(FALSE);
}
return (detect);
}
/* Leave a line of light in given dir, blue light can sometimes */
/* hurt creatures. -RAK- */
void
light_line(dir, y, x)
int dir, y, x;
{
register cave_type *c_ptr;
int dist, flag;
dist = (-1);
flag = FALSE;
do {
/* put mmove at end because want to light up current spot */
dist++;
c_ptr = &cave[y][x];
if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
flag = TRUE;
if (!c_ptr->pl && !c_ptr->tl) {
/* set pl so that lite_spot will work */
c_ptr->pl = TRUE;
if (c_ptr->fval == LIGHT_FLOOR) {
if (panel_contains(y, x))
light_room(y, x);
} else
lite_spot(y, x);
}
/* set pl in case tl was true above */
c_ptr->pl = TRUE;
mon_light_dam(y, x, damroll(6, 8));
(void)mmove(dir, &y, &x);
}
while (!flag);
}
/* Light line in all directions -RAK- */
void
starlite(y, x)
register int y, x;
{
register int i;
if (py.flags.blind < 1)
msg_print("The end of the staff bursts into a blue shimmering light.");
for (i = 1; i <= 9; i++)
if (i != 5)
light_line(i, y, x);
}
/* Disarms all traps/chests in a given direction -RAK- */
int
disarm_all(dir, y, x)
int dir, y, x;
{
register cave_type *c_ptr;
register inven_type *t_ptr;
register int disarm, dist;
disarm = FALSE;
dist = (-1);
do {
/* put mmove at end, in case standing on a trap */
dist++;
c_ptr = &cave[y][x];
/* note, must continue upto and including the first non open space,
* because secret doors have fval greater than MAX_OPEN_SPACE
*/
if (c_ptr->tptr != 0) {
t_ptr = &t_list[c_ptr->tptr];
if ((t_ptr->tval == TV_INVIS_TRAP) || (t_ptr->tval == TV_VIS_TRAP)) {
if (delete_object(y, x))
disarm = TRUE;
} else if (t_ptr->tval == TV_CLOSED_DOOR)
t_ptr->p1 = 0; /* Locked or jammed doors become merely closed. */
else if (t_ptr->tval == TV_SECRET_DOOR) {
c_ptr->fm = TRUE;
change_trap(y, x);
disarm = TRUE;
} else if ((t_ptr->tval == TV_CHEST) && (t_ptr->flags != 0)) {
msg_print("Click!");
t_ptr->flags &= ~(CH_TRAPPED | CH_LOCKED);
disarm = TRUE;
t_ptr->name2 = SN_UNLOCKED;
known2(t_ptr);
}
}
(void)mmove(dir, &y, &x);
}
while ((dist <= OBJ_BOLT_RANGE) && c_ptr->fval <= MAX_OPEN_SPACE);
return (disarm);
}
/* Shoot a bolt in a given direction -RAK- */
void
fire_bolt(typ, dir, y, x, dam_hp)
int typ, dir, y, x, dam_hp;
{
int i, oldy, oldx, dist, flag;
/* int32u harm_type = 0; */
register cave_type *c_ptr;
register monster_type *m_ptr;
register creature_type *r_ptr;
vtype out_val, m_name;
int dam = dam_hp;
int ny, nx;
char bolt_char;
flag = FALSE;
oldy = y;
oldx = x;
dist = 0;
do {
ny = y;
nx = x;
(void)mmove(dir, &y, &x);
/* choose the right shape for the bolt... -CFT */
if (ny == y)
bolt_char = '-';
else if (nx == x)
bolt_char = '|';
else if ((ny - y) == (nx - x))
bolt_char = '\\';
else
bolt_char = '/';
dist++;
c_ptr = &cave[y][x];
lite_spot(oldy, oldx);
if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
flag = TRUE;
else {
if (c_ptr->cptr > 1) {
flag = TRUE;
m_ptr = &m_list[c_ptr->cptr];
r_ptr = &c_list[m_ptr->mptr];
/*
* light up monster and draw monster, temporarily set pl so that
* update_mon() will work
*/
i = c_ptr->pl;
c_ptr->pl = TRUE;
update_mon((int)c_ptr->cptr);
c_ptr->pl = i;
/* draw monster and clear previous bolt */
put_qio();
spell_hit_monster(m_ptr, typ, &dam, 0, &ny, &nx, TRUE);
c_ptr = &cave[ny][nx]; /* may be new location if teleported
* by gravity warp... */
m_ptr = &m_list[c_ptr->cptr]; /* and even if not, may be
* new monster if chaos
* polymorphed */
r_ptr = &c_list[m_ptr->mptr];
monster_name(m_name, m_ptr, r_ptr);
if ((dam > 0) && (m_ptr->hp >= dam)) {
(void)sprintf(out_val,
pain_message((int)c_ptr->cptr, dam), m_name);
msg_print(out_val);
}
i = mon_take_hit((int)c_ptr->cptr, dam, TRUE);
if (i >= 0)
prt_experience();
} else if (panel_contains(y, x) && (py.flags.blind < 1)) {
print(bolt_char, y, x);
/* show the bolt */
put_qio();
#ifdef MSDOS
delay(8 * delay_spd); /* milliseconds */
#else
usleep(8000 * delay_spd); /* useconds */
#endif
}
}
oldy = y;
oldx = x;
#ifdef TARGET
if (target_mode && at_target(y,x))
flag = TRUE; /* must have hit "targeted" area -CFT */
#endif
}
while (!flag);
lite_spot(oldy, oldx); /* just in case, clear any leftover bolt images -CFT */
}
/* Shoot a bolt in a given direction -RAK- */
/* heavily modified to include exotic bolts -CFT */
void
bolt(typ, y, x, dam_hp, ddesc, ptr, monptr)
int typ, y, x, dam_hp;
char *ddesc;
monster_type *ptr;
int monptr;
{
int i = ptr->fy, j = ptr->fx;
int dam;
int32u tmp, treas;
register cave_type *c_ptr;
register monster_type *m_ptr;
register creature_type *r_ptr;
char bolt_char;
int blind = (py.flags.status & PY_BLIND) ? 1 : 0;
int ny, nx, sourcey, sourcex, dist;
vtype m_name, out_val;
sourcey = i;
sourcex = j;
dist = 0;
do {
/* This is going along a badly angled line so call mmove2 direct */
ny = i;
nx = j;
mmove2(&i, &j, sourcey, sourcex, char_row, char_col);
dist++;
/* choose the right shape for the bolt... -CFT */
if (ny == i)
bolt_char = '-';
else if (nx == j)
bolt_char = '|';
else if ((ny - i) == (nx - j))
bolt_char = '\\';
else
bolt_char = '/';
if (in_bounds(i, j) && los(y, x, i, j)) {
c_ptr = &cave[i][j];
if (c_ptr->fval <= MAX_OPEN_SPACE) {
if (panel_contains(i, j) && !(py.flags.status & PY_BLIND)) {
print(bolt_char, i, j);
put_qio();
#ifdef MSDOS
delay(8 * delay_spd); /* milliseconds */
#else
usleep(8000 * delay_spd); /* useconds */
#endif
lite_spot(i, j);
}
if (c_ptr->cptr > 1 && c_ptr->cptr != monptr) {
m_ptr = &m_list[c_ptr->cptr];
dam = dam_hp;
spell_hit_monster(m_ptr, typ, &dam, 0, &ny, &nx, FALSE);
/* process hit effects */
/* may be new location if teleported by gravity warp... */
c_ptr = &cave[ny][nx];
/* and even if not, may be new monster if chaos polymorphed */
m_ptr = &m_list[c_ptr->cptr];
r_ptr = &c_list[m_ptr->mptr];
monster_name(m_name, m_ptr, r_ptr);
if (dam < 1)
dam = 1; /* protect vs neg damage -CFT */
m_ptr->hp = m_ptr->hp - dam;
m_ptr->csleep = 0;
/* prevent unique monster from death by other monsters. It causes trouble
* (monster not marked as dead, quest monsters don't satisfy quest, etc).
* So, we let them live, but extremely wimpy. -CFT
*/
if ((r_ptr->cdefense & UNIQUE) && (m_ptr->hp < 0))
m_ptr->hp = 0;
if (m_ptr->hp < 0) {
object_level = (dun_level + r_ptr->level) >> 1;
coin_type = 0;
get_coin_type(r_ptr);
treas = monster_death((int)m_ptr->fy, (int)m_ptr->fx,
r_ptr->cmove, 0, 0);
coin_type = 0;
if (m_ptr->ml || (c_list[m_ptr->mptr].cdefense & UNIQUE)) {
tmp = (c_recall[m_ptr->mptr].r_cmove & CM_TREASURE)
>> CM_TR_SHIFT;
if (tmp > ((treas & CM_TREASURE) >> CM_TR_SHIFT))
treas = (treas & ~CM_TREASURE) | (tmp << CM_TR_SHIFT);
c_recall[m_ptr->mptr].r_cmove = treas |
(c_recall[m_ptr->mptr].r_cmove & ~CM_TREASURE);
}
if (monptr < c_ptr->cptr)
delete_monster((int)c_ptr->cptr);
else
fix1_delete_monster((int)c_ptr->cptr);
} else {
(void)sprintf(out_val, pain_message((int)c_ptr->cptr, dam),
m_name);
msg_print(out_val);
}
break;
} else if (c_ptr->cptr == 1) {
if (dam_hp < 1)
dam_hp = 1;
m_ptr = &m_list[monptr];
switch (typ) {
case GF_LIGHTNING:
if (blind)
msg_print("You are hit by electricity!");
light_dam(dam_hp, ddesc);
break;
case GF_POISON_GAS:
if (blind)
msg_print("You are hit by a blast of noxious gases!");
poison_gas(dam_hp, ddesc);
break;
case GF_ACID:
if (blind)
msg_print("You are hit by a jet of acidic fluid!");
acid_dam(dam_hp, ddesc);
break;
case GF_FROST:
if (blind)
msg_print("You are hit by something cold!");
cold_dam(dam_hp, ddesc);
break;
case GF_FIRE:
if (blind)
msg_print("You are hit by something hot!");
fire_dam(dam_hp, ddesc);
break;
case GF_MAGIC_MISSILE:
if (blind)
msg_print("You are hit by something!");
take_hit(dam_hp, ddesc);
break;
case GF_HOLY_ORB:
if (blind)
msg_print("You are hit by something!");
dam_hp /= 2; /* player should take less damage
* -CFT */
take_hit(dam_hp, ddesc);
break;
case GF_ARROW: /* maybe can miss? */
if (blind)
msg_print("You are hit by something!");
take_hit(dam_hp, ddesc);
break;
case GF_PLASMA: /* no resist to plasma? */
if (blind)
msg_print("You are hit by something!");
take_hit(dam_hp, ddesc);
break;
case GF_NETHER:
if (blind)
msg_print("You are hit by an unholy blast!");
if (py.flags.nether_resist) {
dam_hp *= 6; /* these 2 lines give avg dam
* of .655, ranging from */
dam_hp /= (randint(6) + 6); /* .858 to .5 -CFT */
} else { /* no resist */
if (py.flags.hold_life && randint(5) > 1)
msg_print("You keep hold of your life force!");
else if (py.flags.hold_life) {
msg_print("You feel your life slipping away!");
lose_exp(200 + (py.misc.exp / 1000) * MON_DRAIN_LIFE);
} else {
msg_print("You feel your life draining away!");
lose_exp(200 + (py.misc.exp / 100) * MON_DRAIN_LIFE);
}
}
take_hit(dam_hp, ddesc);
break;
case GF_WATER:
if (blind)
msg_print("You are hit by a jet of water!");
if (!py.flags.sound_resist)
stun_player(randint(15));
take_hit(dam_hp, ddesc);
break;
case GF_CHAOS:
if (blind)
msg_print("You are hit by wave of entropy!");
if (py.flags.chaos_resist) {
dam_hp *= 6; /* these 2 lines give avg dam
* of .655, ranging from */
dam_hp /= (randint(6) + 6); /* .858 to .5 -CFT */
}
if ((!py.flags.confusion_resist) && (!py.flags.chaos_resist)) {
if (py.flags.confused > 0)
py.flags.confused += 12;
else
py.flags.confused = randint(20) + 10;
}
if (!py.flags.chaos_resist)
py.flags.image += randint(10);
take_hit(dam_hp, ddesc);
break;
case GF_SHARDS:
if (blind)
msg_print("You are cut by sharp fragments!");
if (py.flags.shards_resist) {
dam_hp *= 6; /* these 2 lines give avg dam
* of .655, ranging from */
dam_hp /= (randint(6) + 6); /* .858 to .5 -CFT */
} else {
cut_player(dam_hp); /* ouch! */
}
take_hit(dam_hp, ddesc);
break;
case GF_SOUND:
if (blind)
msg_print("You are deafened by a blast of noise!");
if (py.flags.sound_resist) {
dam_hp *= 5;
dam_hp /= (randint(6) + 6);
} else {
stun_player(randint((dam_hp > 60) ? 25 : (dam_hp / 3 + 5)));
}
take_hit(dam_hp, ddesc);
break;
case GF_CONFUSION:
if (blind)
msg_print("You are hit by a wave of dizziness!");
if (py.flags.confusion_resist) {
dam_hp *= 5;
dam_hp /= (randint(6) + 6);
}
if (!py.flags.confusion_resist && !py.flags.chaos_resist) {
if (py.flags.confused > 0)
py.flags.confused += 8;
else
py.flags.confused = randint(15) + 5;
}
take_hit(dam_hp, ddesc);
break;
case GF_DISENCHANT:
if (blind)
msg_print("You are hit by something!");
if (py.flags.disenchant_resist) {
dam_hp *= 6; /* these 2 lines give avg dam
* of .655, ranging from */
dam_hp /= (randint(6) + 6); /* .858 to .5 -CFT */
} else {
int8u disenchant = FALSE;
int8u chance;
int t = 0;
inven_type *i_ptr;
switch (randint(7)) {
case 1:
t = INVEN_BODY;
break;
case 2:
t = INVEN_BODY;
break;
case 3:
t = INVEN_ARM;
break;
case 4:
t = INVEN_OUTER;
break;
case 5:
t = INVEN_HANDS;
break;
case 6:
t = INVEN_HEAD;
break;
case 7:
t = INVEN_FEET;
break;
}
i_ptr = &inventory[t];
chance = 1;
if (i_ptr->flags2 & TR_ARTIFACT) /* Artifacts have 2/3 */
chance = randint(3); /* chance to resist -DGK */
if ((i_ptr->tohit > 0) && (chance == 1)) {
i_ptr->tohit -= randint(2);
/* don't send it below zero */
if (i_ptr->tohit < 0)
i_ptr->tohit = 0;
disenchant = TRUE;
}
if ((i_ptr->todam > 0) && (chance == 1)) {
i_ptr->todam -= randint(2);
/* don't send it below zero */
if (i_ptr->todam < 0)
i_ptr->todam = 0;
disenchant = TRUE;
}
if ((i_ptr->toac > 0) && (chance == 1)) {
i_ptr->toac -= randint(2);
/* don't send it below zero */
if (i_ptr->toac < 0)
i_ptr->toac = 0;
disenchant = TRUE;
}
if (disenchant || (chance != 1)) {
vtype t1, t2;
objdes(t1, &inventory[t], FALSE);
if (chance != 1)
sprintf(t2, "Your %s (%c) %s disenchanted!", t1,
i + 'a' - INVEN_WIELD,
(inventory[i].number != 1) ? "were" : "was");
else
sprintf(t2, "Your %s (%c) %s disenchantment!", t1,
i + 'a' - INVEN_WIELD,
(inventory[i].number != 1) ?
"resist" : "resists");
msg_print(t2);
calc_bonuses();
}
}
take_hit(dam_hp, ddesc);
break;
/* no spec. effects from nexus bolt, only breath -CFT */
case GF_NEXUS:
if (blind)
msg_print("You are hit by something strange!");
if (py.flags.nexus_resist) {
dam_hp *= 6; /* these 2 lines give avg dam
* of .655, ranging from */
dam_hp /= (randint(6) + 6); /* .858 to .5 -CFT */
}
take_hit(dam_hp, ddesc);
break;
case GF_FORCE:
if (blind)
msg_print("You are hit hard by a sudden force!");
if (!py.flags.sound_resist)
stun_player(randint(15) + 1);
take_hit(dam_hp, ddesc);
break;
case GF_INERTIA:
if (blind)
msg_print("You are hit by something!");
if ((py.flags.slow > 0) && (py.flags.slow < 32000))
py.flags.slow += randint(5);
else {
msg_print("You feel less able to move.");
py.flags.slow = randint(5) + 3;
}
take_hit(dam_hp, ddesc);
break;
case GF_LIGHT:
if (blind)
msg_print("You are hit by something!");
if (py.flags.light_resist) {
dam_hp *= 4; /* these 2 lines give avg dam
* of .444, ranging from */
dam_hp /= (randint(6) + 6); /* .556 to .333 -CFT */
} else if (!blind && !py.flags.blindness_resist) {
msg_print("You are blinded by the flash!");
py.flags.blind += randint(5) + 2;
}
take_hit(dam_hp, ddesc);
break;
case GF_DARK:
if (blind)
msg_print("You are hit by something!");
if (py.flags.dark_resist) {
dam_hp *= 4; /* these 2 lines give avg dam
* of .444, ranging from */
dam_hp /= (randint(6) + 6); /* .556 to .333 -CFT */
} else {
if (!blind && !py.flags.blindness_resist) {
msg_print("The darkness prevents you from seeing!");
py.flags.blind += randint(5) + 2;
}
}
take_hit(dam_hp, ddesc);
break;
case GF_TIME: /* only some effects from time bolt
* -CFT */
if (blind)
msg_print("You are hit by something!");
if (randint(2) == 1) {
msg_print("You feel life has clocked back.");
lose_exp(m_ptr->hp + (py.misc.exp / 300) * MON_DRAIN_LIFE);
} else {
int t = 0;
switch (randint(6)) {
case 1:
t = A_STR;
msg_print("You're not as strong as you used to be...");
break;
case 2:
t = A_INT;
msg_print("You're not as bright as you used to be...");
break;
case 3:
t = A_WIS;
msg_print("You're not as wise as you used to be...");
break;
case 4:
t = A_DEX;
msg_print("You're not as agile as you used to be...");
break;
case 5:
t = A_CON;
msg_print("You're not as hale as you used to be...");
break;
case 6:
t = A_CHR;
msg_print("You're not as beautiful as you used to be...");
break;
}
py.stats.cur_stat[t] = (py.stats.cur_stat[t] * 3) / 4;
if (py.stats.cur_stat[t] < 3)
py.stats.cur_stat[t] = 3;
set_use_stat(t);
prt_stat(t);
}
take_hit(dam_hp, ddesc);
break;
case GF_GRAVITY:
if (blind)
msg_print("You are hit by a surge of gravity!");
if ((!py.flags.sound_resist) && (!py.flags.ffall)) /* DGK */
stun_player(randint(15) + 1);
if (py.flags.ffall) { /* DGK */
dam_hp *= 3; /* these 2 lines give avg dam
* of .25, ranging from */
dam_hp /= (randint(6) + 6); /* .427 to .25 -CFT */
} else { /* DGK */
if ((py.flags.slow > 0) && (py.flags.slow < 32000))
py.flags.slow += randint(5);
else {
msg_print("You feel less able to move.");
py.flags.slow = randint(5) + 3;
}
} /* DGK */
take_hit(dam_hp, ddesc);
break;
case GF_MANA:
if (blind)
msg_print("You are hit by a beam of power!");
take_hit(dam_hp, ddesc);
break;
case GF_METEOR:
if (blind)
msg_print("You are hit by something!");
take_hit(dam_hp, ddesc);
break;
case GF_ICE:
if (blind)
msg_print("You are hit by something cold and sharp!");
cold_dam(dam_hp, ddesc);
if (!py.flags.sound_resist)
stun_player(randint(15) + 1);
if (!py.flags.shards_resist)
cut_player(damroll(8, 10));
break;
default:
msg_print("Unknown typ in bolt(). This may mean trouble.");
}
disturb(1, 0);
break;
}
}
}
} while ((i != char_row) || (j != char_col));
}
/* Shoot a ball in a given direction. Note that balls have an */
/* area affect. -RAK- */
void
fire_ball(typ, dir, y, x, dam_hp, max_dis)
int typ, dir, y, x, dam_hp, max_dis;
{
register int i, j;
int dam, thit, tkill, k, tmp, monptr;
int oldy, oldx, dist, flag;
int (*destroy) ();
register cave_type *c_ptr;
register monster_type *m_ptr;
register creature_type *r_ptr;
int ny, nx;
char bolt_char;
thit = 0;
tkill = 0;
ball_destroy(typ, &destroy);
flag = FALSE;
oldy = y;
oldx = x;
dist = 0;
do {
ny = y;
nx = x;
/* we don't call mmove if targetting and at target. This allow player to target
* a ball spell at his position, to explode it around himself -CFT
*/
if (dir || !at_target(y,x))
(void)mmove(dir, &y, &x);
/* choose the right shape for the bolt... -CFT */
if (ny == y)
bolt_char = '-';
else if (nx == x)
bolt_char = '|';
else if ((ny - y) == (nx - x))
bolt_char = '\\';
else
bolt_char = '/';
dist++;
lite_spot(oldy, oldx);
if (dist > OBJ_BOLT_RANGE)
flag = TRUE;
else {
c_ptr = &cave[y][x];
/* targeting code stolen from Morgul -CFT */
/* This test has been overhauled (twice): basically, it now says: if
* ((spell hits a wall) OR ((spell hits a creature) and ((not
* targetting) or (at the target anyway) or (no line-of-sight to
* target, so aiming unusable) or ((aiming at a monster) and (that
* monster is unseen, so aiming unusable)))) OR ((we are targetting)
* and (at the target location))) THEN the ball explodes... -CFT
*/
#ifndef TARGET
if ((c_ptr->fval >= MIN_CLOSED_SPACE) ||
((c_ptr->cptr > 1))) {
flag = TRUE; /* THEN we decide to explode here. -CFT */
if (c_ptr->fval >= MIN_CLOSED_SPACE) {
y = oldy;
x = oldx;
}
#else
if ((c_ptr->fval >= MIN_CLOSED_SPACE) ||
((c_ptr->cptr > 1) &&
(!target_mode || at_target(y, x) ||
!los(target_row, target_col, char_row, char_col) ||
((target_mon < MAX_MALLOC) && !m_list[target_mon].ml))) ||
(target_mode && at_target(y, x))) {
flag = TRUE; /* THEN we decide to explode here. -CFT */
if (c_ptr->fval >= MIN_CLOSED_SPACE) {
y = oldy;
x = oldx;
}
#endif
/* The ball hits and explodes. */
/* The explosion. */
for (i = y - max_dis; i <= y + max_dis; i++)
for (j = x - max_dis; j <= x + max_dis; j++)
if (in_bounds(i, j) && (distance(y, x, i, j) <= max_dis) &&
los(char_row, char_col, i, j) && los(y, x, i, j) &&
(cave[i][j].fval <= MAX_OPEN_SPACE) &&
panel_contains(i, j) && (py.flags.blind < 1)) {
#ifdef TC_COLOR
if (!no_color_flag)
textcolor(bolt_color(typ));
#endif
print('*', i, j);
#ifdef TC_COLOR
/* prob don't need here, but... -CFT */
if (!no_color_flag)
textcolor(LIGHTGRAY);
#endif
}
if (py.flags.blind < 1) {
put_qio();
#ifdef MSDOS
delay(25 * delay_spd); /* milliseconds */
#else
usleep(25000 * delay_spd); /* useconds */
#endif
}
/* now erase the ball, since effects below may use msg_print, and
* pause indefinitely, so we want ball gone before then -CFT
*/
for (i = y - max_dis; i <= y + max_dis; i++)
for (j = x - max_dis; j <= x + max_dis; j++)
if (in_bounds(i, j) && (distance(y, x, i, j) <= max_dis) &&
los(char_row, char_col, i, j) && los(y, x, i, j) &&
(cave[i][j].fval <= MAX_OPEN_SPACE) &&
panel_contains(i, j) && (py.flags.blind < 1)) {
lite_spot(i, j); /* draw what is below the '*' */
}
put_qio();
/* First go over the area of effect, and destroy items... Any
* preexisting items will be affected, but items dropped by
* killed monsters are assummed to have been "shielded" from the
* effects the the monster's corpse. This means that you no
* longer have to be SO paranoid about using fire/frost/acid
* balls. -CFT
*/
for (i = y - max_dis; i <= y + max_dis; i++)
for (j = x - max_dis; j <= x + max_dis; j++)
if (in_bounds(i, j) && (distance(y, x, i, j) <= max_dis)
&& los(y, x, i, j) && (cave[i][j].tptr != 0) &&
(*destroy) (&t_list[cave[i][j].tptr]))
(void)delete_object(i, j);
/* burn/corrode or OW destroy items in area of effect */
/* now go over area of affect and DO something to monsters... */
for (i = y - max_dis; i <= y + max_dis; i++)
for (j = x - max_dis; j <= x + max_dis; j++)
if (in_bounds(i, j) && (distance(y, x, i, j) <= max_dis)
&& los(y, x, i, j)) {
c_ptr = &cave[i][j];
if (c_ptr->fval <= MAX_OPEN_SPACE) {
if (c_ptr->cptr > 1) {
dam = dam_hp;
m_ptr = &m_list[c_ptr->cptr];
spell_hit_monster(m_ptr, typ, &dam,
(distance(i, j, y, x) + 1), &ny, &nx, TRUE);
c_ptr = &cave[ny][nx];
/* may be new location if teleported by gravity warp... */
m_ptr = &m_list[c_ptr->cptr];
/* and even if not, may be new monster if chaos polymorphed */
r_ptr = &c_list[m_ptr->mptr];
monptr = c_ptr->cptr;
/*
* lite up creature if visible, temp set pl
* so that update_mon works
*/
tmp = c_ptr->pl;
c_ptr->pl = TRUE;
update_mon((int)c_ptr->cptr);
thit++;
if (dam < 1)
dam = 1; /* protect vs neg damage -CFT */
k = mon_take_hit((int)c_ptr->cptr, dam, TRUE);
if (k >= 0)
tkill++;
c_ptr->pl = tmp;
}
lite_spot(i, j); /* erase the ball... */
}
}
/* show ball of whatever */
put_qio();
/* End explosion. */
if (tkill == 1) {
msg_print("There is a scream of agony!");
} else if (tkill > 1) {
msg_print("There are several screams of agony!");
}
if (tkill >= 0)
prt_experience();
/* End ball hitting. */
} else if (panel_contains(y, x) && (py.flags.blind < 1)) {
#ifdef TC_COLOR
if (!no_color_flag)
textcolor(bolt_color(typ));
#endif
print(bolt_char, y, x);
put_qio();
#ifdef TC_COLOR
if (!no_color_flag)
textcolor(LIGHTGRAY);
#endif
#ifdef MSDOS
delay(8 * delay_spd); /* milliseconds */
#else
usleep(8000 * delay_spd); /* useconds */
#endif
}
oldy = y;
oldx = x;
#ifdef TARGET
if (target_mode && at_target(y,x))
flag = TRUE; /* must have hit "targetted" area -CFT */
#endif
}
} while (!flag);
}
/* Lightning ball in all directions SM */
void
starball(y, x)
register int y, x;
{
register int i;
for (i = 1; i <= 9; i++)
if (i != 5)
fire_ball(GF_LIGHTNING, i, y, x, 150, 3);
}
/* Breath weapon works like a fire_ball, but affects the player. */
/* Note the area affect. -RAK- */
void
breath(typ, y, x, dam_hp, ddesc, monptr)
int typ, y, x, dam_hp;
char *ddesc;
int monptr;
{
register int i, j;
int dam, max_dis;
int32u tmp, treas;
int (*destroy) ();
register cave_type *c_ptr;
register monster_type *m_ptr;
register creature_type *r_ptr;
int ny, nx;
int blind = (py.flags.status & PY_BLIND) ? 1 : 0;
char ch;
m_ptr = &m_list[monptr];
r_ptr = &c_list[m_ptr->mptr];
ch = r_ptr->cchar;
if ((ch == 'v' || ch == 'D' || ch == 'E' || ch == '&' || ch == 'A') ||
((ch == 'd' || ch == 'R') && r_ptr->cdefense & UNIQUE))
max_dis = 3;
else
max_dis = 2;
ball_destroy(typ, &destroy);
if (!(py.flags.status & PY_BLIND)) { /* only bother if the player can see */
for (i = y - max_dis; i <= y + max_dis; i++)
for (j = x - max_dis; j <= x + max_dis; j++)
if (in_bounds(i, j) && (distance(y, x, i, j) <= max_dis) &&
los(y, x, i, j) && (cave[i][j].fval <= MAX_OPEN_SPACE) &&
panel_contains(i, j)) {
#ifdef TC_COLOR
if (!no_color_flag)
textcolor(bolt_color(typ));
#endif
print('*', i, j);
#ifdef TC_COLOR
if (!no_color_flag)
textcolor(LIGHTGRAY); /* prob don't need here, but... -CFT */
#endif
}
put_qio();
#ifdef MSDOS
delay(25 * delay_spd); /* milliseconds */
#else
usleep(25000 * delay_spd); /* useconds */
#endif
/* now erase the ball, since effects below may use msg_print, and pause
* indefinitely, so we want ball gone before then -CFT
*/
for (i = y - max_dis; i <= y + max_dis; i++)
for (j = x - max_dis; j <= x + max_dis; j++)
if (in_bounds(i, j) && (distance(y, x, i, j) <= max_dis) &&
los(y, x, i, j) && (cave[i][j].fval <= MAX_OPEN_SPACE) &&
panel_contains(i, j))
lite_spot(i, j); /* draw what is below the '*' */
put_qio();
}
/* first, go over area of affect and destroy preexisting items. This change
* means that any treasure dropped by killed monsters is safe from the effects
* of this ball (but not from any later balls/breathes, even if they happen
* before the player gets a chance to pick up that scroll of *Acquirement*).
* The assumption is made that this treasure was shielded from the effects by
* the corpse of the killed monster. -CFT
*/
for (i = y - max_dis; i <= y + max_dis; i++)
for (j = x - max_dis; j <= x + max_dis; j++)
if (in_bounds(i, j) && (distance(y, x, i, j) <= max_dis)
&& los(y, x, i, j) && (cave[i][j].tptr != 0)
&& (*destroy) (&t_list[cave[i][j].tptr]))
delete_object(i, j);
/* now go over area of affect and DO something to monsters */
for (i = y - max_dis; i <= y + max_dis; i++)
for (j = x - max_dis; j <= x + max_dis; j++)
if (in_bounds(i, j) && (distance(y, x, i, j) <= max_dis)
&& los(y, x, i, j)) {
c_ptr = &cave[i][j];
if ((c_ptr->tptr != 0) && (*destroy) (&t_list[c_ptr->tptr]))
(void)delete_object(i, j);
if (c_ptr->fval <= MAX_OPEN_SPACE) {
if ((c_ptr->cptr > 1) && (c_ptr->cptr != monptr)) {
dam = dam_hp;
m_ptr = &m_list[c_ptr->cptr];
spell_hit_monster(m_ptr, typ, &dam, distance(i, j, y, x) + 1,
&ny, &nx, FALSE);
c_ptr = &cave[ny][nx]; /* may be new location if teleported
* by gravity warp... */
m_ptr = &m_list[c_ptr->cptr]; /* and even if not, may be new
* monster if chaos polymorphed */
r_ptr = &c_list[m_ptr->mptr];
/*
* can not call mon_take_hit here, since player does not
* get experience for kill
*/
if (dam < 1)
dam = 1;
m_ptr->hp = m_ptr->hp - dam;
m_ptr->csleep = 0;
/* prevent unique monster from death by other monsters. It causes trouble (monster not
* marked as dead, quest monsters don't satisfy quest, etc). So, we let
* them live, but extremely wimpy. This isn't great, because monster might heal
* itself before player's next swing... -CFT
*/
if ((r_ptr->cdefense & UNIQUE) && (m_ptr->hp < 0))
m_ptr->hp = 0;
if (m_ptr->hp < 0) {
object_level = (dun_level + r_ptr->level) >> 1;
coin_type = 0;
get_coin_type(r_ptr);
treas = monster_death((int)m_ptr->fy, (int)m_ptr->fx,
r_ptr->cmove, 0, 0);
coin_type = 0;
/* recall even invisible uniques -CWS */
if (m_ptr->ml || (c_list[m_ptr->mptr].cdefense & UNIQUE)) {
tmp = (c_recall[m_ptr->mptr].r_cmove & CM_TREASURE)
>> CM_TR_SHIFT;
if (tmp > ((treas & CM_TREASURE) >> CM_TR_SHIFT))
treas = (treas & ~CM_TREASURE) | (tmp << CM_TR_SHIFT);
c_recall[m_ptr->mptr].r_cmove = treas |
(c_recall[m_ptr->mptr].r_cmove & ~CM_TREASURE);
}
/* It ate an already processed monster. Handle normally. */
if (monptr < c_ptr->cptr)
delete_monster((int)c_ptr->cptr);
/* If it eats this monster, an already processed monster will take its place,
* causing all kinds of havoc. Delay the kill a bit.
*/
else
fix1_delete_monster((int)c_ptr->cptr);
}
} else if (c_ptr->cptr == 1) {
dam = (dam_hp / (distance(i, j, y, x) + 1));
m_ptr = &m_list[monptr];
/* let's do at least one point of damage */
/* prevents randint(0) problem with poison_gas, also */
if (dam <= 0)
dam = 1;
if (dam > 1600)
dam = 1600;
switch (typ) {
case GF_LIGHTNING:
light_dam(dam, ddesc);
break;
case GF_POISON_GAS:
poison_gas(dam, ddesc);
break;
case GF_ACID:
acid_dam(dam, ddesc);
break;
case GF_FROST:
cold_dam(dam, ddesc);
break;
case GF_FIRE:
fire_dam(dam, ddesc);
break;
case GF_MAGIC_MISSILE:
take_hit(dam, ddesc);
break;
case GF_HOLY_ORB:
dam /= 2; /* player should take less damage
* from "good" power-CFT */
take_hit(dam, ddesc);
break;
case GF_ARROW: /* maybe can miss? */
take_hit(dam, ddesc);
break;
case GF_PLASMA: /* no resist to plasma? */
take_hit(dam, ddesc);
if (!py.flags.sound_resist)
stun_player(randint(
(dam_hp > 40) ? 35 : (dam_hp * 3 / 4 + 5)));
break;
case GF_NETHER:
if (py.flags.nether_resist) {
dam *= 6; /* these 2 lines give avg dam
* of .655, ranging from */
dam /= (randint(5) + 6); /* .858 to .5 -CFT */
} else { /* no resist */
if (py.flags.hold_life && randint(3) > 1)
msg_print("You keep hold of your life force!");
else if (py.flags.hold_life) {
msg_print("You feel your life slipping away!");
lose_exp(200 + (py.misc.exp/1000) * MON_DRAIN_LIFE);
} else {
msg_print("You feel your life draining away!");
lose_exp(200 + (py.misc.exp/100) * MON_DRAIN_LIFE);
}
}
take_hit(dam, ddesc);
break;
case GF_WATER:
if (!py.flags.sound_resist)
stun_player(randint(55));
if (!player_saves() && !py.flags.confusion_resist
&& !py.flags.chaos_resist) {
if ((py.flags.confused > 0) &&
(py.flags.confused < 32000))
py.flags.confused += 6;
else
py.flags.confused = randint(8) + 6;
}
take_hit(dam, ddesc);
break;
case GF_CHAOS:
if (py.flags.chaos_resist) {
dam *= 6; /* these 2 lines give avg dam
* of .655, ranging from */
dam /= (randint(6) + 6); /* .858 to .5 -CFT */
}
if ((!py.flags.confusion_resist) &&
(!py.flags.chaos_resist)) {
if (py.flags.confused > 0)
py.flags.confused += 12;
else
py.flags.confused = randint(20) + 10;
}
if (!py.flags.chaos_resist)
py.flags.image += randint(10);
if (!py.flags.nether_resist && !py.flags.chaos_resist) {
if (py.flags.hold_life && randint(3) > 1)
msg_print("You keep hold of your life force!");
else if (py.flags.hold_life) {
msg_print("You feel your life slipping away!");
lose_exp(500 + (py.misc.exp/1000) * MON_DRAIN_LIFE);
} else {
msg_print("You feel your life draining away!");
lose_exp(5000 + (py.misc.exp/100) * MON_DRAIN_LIFE);
}
}
take_hit(dam, ddesc);
break;
case GF_SHARDS:
if (py.flags.shards_resist) {
dam *= 6; /* these 2 lines give avg dam
* of .655, ranging from */
dam /= (randint(6) + 6); /* .858 to .5 -CFT */
} else {
cut_player(dam); /* ouch! */
}
take_hit(dam, ddesc);
break;
case GF_SOUND:
if (py.flags.sound_resist) {
dam *= 5;
dam /= (randint(6) + 6);
} else {
stun_player(randint((dam > 90) ? 35 : (dam / 3 + 5)));
}
take_hit(dam, ddesc);
break;
case GF_CONFUSION:
if (py.flags.confusion_resist) {
dam *= 5; /* these 2 lines give avg dam
* of .655, ranging from */
dam /= (randint(6) + 6); /* .858 to .5 -CFT */
}
if (!py.flags.confusion_resist && !py.flags.chaos_resist) {
if (py.flags.confused > 0)
py.flags.confused += 12;
else
py.flags.confused = randint(20) + 10;
}
take_hit(dam, ddesc);
break;
case GF_DISENCHANT:
if (py.flags.disenchant_resist) {
dam *= 6; /* these 2 lines give avg dam
* of .655, ranging from */
dam /= (randint(6) + 6); /* .858 to .5 -CFT */
} else {
int8u disenchant = FALSE;
int8u chance;
int t = 0;
inven_type *i_ptr;
switch (randint(7)) {
case 1:
t = INVEN_BODY;
break;
case 2:
t = INVEN_BODY;
break;
case 3:
t = INVEN_ARM;
break;
case 4:
t = INVEN_OUTER;
break;
case 5:
t = INVEN_HANDS;
break;
case 6:
t = INVEN_HEAD;
break;
case 7:
t = INVEN_FEET;
break;
}
i_ptr = &inventory[t];
chance = 1;
/* Artifacts have 2/3 chance to resist -DGK */
if (i_ptr->flags2 & TR_ARTIFACT)
chance = randint(3);
if ((i_ptr->tohit > 0) && (chance == 1)) {
i_ptr->tohit -= randint(2);
/* don't send it below zero */
if (i_ptr->tohit < 0)
i_ptr->tohit = 0;
disenchant = TRUE;
}
if ((i_ptr->todam > 0) && (chance == 1)) {
i_ptr->todam -= randint(2);
/* don't send it below zero */
if (i_ptr->todam < 0)
i_ptr->todam = 0;
disenchant = TRUE;
}
if ((i_ptr->toac > 0) && (chance == 1)) {
i_ptr->toac -= randint(2);
/* don't send it below zero */
if (i_ptr->toac < 0)
i_ptr->toac = 0;
disenchant = TRUE;
}
if (disenchant || (chance != 1)) {
vtype t1, t2;
objdes(t1, &inventory[t], FALSE);
if (chance != 1)
sprintf(t2, "Your %s (%c) %s disenchanted!", t1,
i + 'a' - INVEN_WIELD,
(inventory[i].number != 1) ?
"were" : "was");
else
sprintf(t2, "Your %s (%c) %s disenchantment!",
t1,
i + 'a' - INVEN_WIELD,
(inventory[i].number != 1) ?
"resist" : "resists");
msg_print(t2);
calc_bonuses();
}
}
take_hit(dam, ddesc);
break;
case GF_NEXUS:
/* no spec. effects from nexus bolt, only breath -CFT */
if (py.flags.nexus_resist) {
dam *= 6; /* these 2 lines give avg dam
* of .655, ranging from */
dam /= (randint(6) + 6); /* .858 to .5 -CFT */
} else { /* special effects */
switch (randint(7)) {
case 1:
case 2:
case 3:
teleport(200);
break;
case 4:
case 5:
teleport_to((int)m_ptr->fy, (int)m_ptr->fx);
break;
case 6:
if (player_saves())
msg_print("You resist the effects.");
else {
int k = dun_level;
if (dun_level == Q_PLANE)
dun_level = 0;
else if (is_quest(dun_level))
dun_level -= 1;
else
dun_level += (-3) + 2 * randint(2);
if (dun_level < 0)
dun_level = 0;
if (k == Q_PLANE)
msg_print("You warp through a cross-dimension gate.");
else if (k < dun_level)
msg_print("You sink through the floor.");
else
msg_print("You rise up through the ceiling.");
new_level_flag = TRUE;
}
break;
case 7:
if (player_saves() && randint(2) == 1)
msg_print("You resist the effects.");
else {
int max1, cur1, max2, cur2, ii, jj;
msg_print("Your body starts to scramble...");
ii = randint(6) - 1;
do {
jj = randint(6) - 1;
} while (ii == jj);
max1 = py.stats.max_stat[ii];
cur1 = py.stats.cur_stat[ii];
max2 = py.stats.max_stat[jj];
cur2 = py.stats.cur_stat[jj];
py.stats.max_stat[ii] = max2;
py.stats.cur_stat[ii] = cur2;
py.stats.max_stat[jj] = max1;
py.stats.cur_stat[jj] = cur1;
set_use_stat(ii);
set_use_stat(jj);
prt_stat(ii);
prt_stat(jj);
}
} /* switch for effects */
}
take_hit(dam, ddesc);
break;
case GF_FORCE:
if (!py.flags.sound_resist)
stun_player(randint(20));
take_hit(dam, ddesc);
break;
case GF_INERTIA:
if ((py.flags.slow > 0) && (py.flags.slow < 32000))
py.flags.slow += randint(5);
else {
msg_print("You feel less able to move.");
py.flags.slow = randint(5) + 3;
}
take_hit(dam, ddesc);
break;
case GF_LIGHT:
if (py.flags.light_resist) {
dam *= 4;
dam /= (randint(6) + 6);
} else if (!blind && !py.flags.blindness_resist) {
msg_print("You are blinded by the flash!");
py.flags.blind += randint(6) + 3;
}
light_area(char_row, char_col, 0, max_dis);
take_hit(dam, ddesc);
break;
case GF_DARK:
if (py.flags.dark_resist) {
dam *= 4;
dam /= (randint(6) + 6);
} else {
if (!blind)
msg_print("The darkness prevents you from seeing!");
py.flags.blind += randint(5) + 2;
}
unlight_area(char_row, char_col);
take_hit(dam, ddesc);
break;
case GF_TIME: /* only some effects from
* time bolt -CFT */
switch (randint(10)) {
case 1:
case 2:
case 3:
case 4:
case 5:
msg_print("You feel life has clocked back.");
lose_exp(m_ptr->hp + (py.misc.exp / 300) * MON_DRAIN_LIFE);
break;
case 6:
case 7:
case 8:
case 9:
{
int t = 0;
switch (randint(6)) {
case 1:
t = A_STR;
msg_print("You're not as strong as you used to be...");
break;
case 2:
t = A_INT;
msg_print("You're not as bright as you used to be...");
break;
case 3:
t = A_WIS;
msg_print("You're not as wise as you used to be...");
break;
case 4:
t = A_DEX;
msg_print("You're not as agile as you used to be...");
break;
case 5:
t = A_CON;
msg_print("You're not as hale as you used to be...");
break;
case 6:
t = A_CHR;
msg_print("You're not as beautiful as you used to be...");
break;
}
py.stats.cur_stat[t] = (py.stats.cur_stat[t] * 3) / 4;
if (py.stats.cur_stat[t] < 3)
py.stats.cur_stat[t] = 3;
set_use_stat(t);
prt_stat(t);
}
break;
case 10:
{
int ii;
for (ii = 0; ii < 6; ii++) {
py.stats.cur_stat[ii] = (py.stats.cur_stat[ii] * 3) / 4;
if (py.stats.cur_stat[ii] < 3)
py.stats.cur_stat[ii] = 3;
set_use_stat(ii);
prt_stat(ii);
}
}
msg_print("You're not as strong as you used to be...");
msg_print("You're not as bright as you used to be...");
msg_print("You're not as wise as you used to be...");
msg_print("You're not as agile as you used to be...");
msg_print("You're not as hale as you used to be...");
msg_print("You're not as beautiful as you used to be...");
break;
} /* randint(10) for effects */
take_hit(dam, ddesc);
break;
case GF_GRAVITY:
if ((!py.flags.sound_resist) && (!py.flags.ffall)) /* DGK */
stun_player(randint((dam > 90) ? 35 : (dam / 3 + 5)));
if (py.flags.ffall) { /* DGK */
dam_hp *= 3; /* these 2 lines give avg dam
* of .33, ranging from */
dam_hp /= (randint(6) + 6); /* .427 to .25 -CFT */
} else { /* DGK */
if ((py.flags.slow > 0) && (py.flags.slow < 32000))
py.flags.slow += randint(5);
else {
msg_print("You feel less able to move.");
py.flags.slow = randint(5) + 3;
}
} /* DGK */
msg_print("Gravity warps around you.");
teleport(5);
take_hit(dam, ddesc);
break;
case GF_MANA:
take_hit(dam, ddesc);
break;
case GF_METEOR:
take_hit(dam, ddesc);
break;
case GF_ICE:
cold_dam(dam, ddesc);
if (!py.flags.sound_resist)
stun_player(randint(25));
if (!py.flags.shards_resist)
cut_player(damroll(8, 10));
break;
default:
msg_print("Unknown typ in breath(). This may mean trouble.");
}
}
}
}
/* show the ball of gas */
put_qio();
/* erase ball and redraw */
for (i = (y - max_dis); i <= (y + max_dis); i++)
for (j = (x - max_dis); j <= (x + max_dis); j++)
if (in_bounds(i, j) && panel_contains(i, j) &&
(distance(y, x, i, j) <= max_dis))
lite_spot(i, j);
}
int
recharge(num)
register int num;
{
int i, j, k, l, item_val;
register int res;
register inven_type *i_ptr;
int found = FALSE;
res = FALSE;
if (find_range(TV_STAFF, TV_WAND, &i, &j))
found = TRUE;
if (find_range(TV_ROD, TV_NEVER, &k, &l))
found = TRUE;
if (!found)
msg_print("You have nothing to recharge.");
else if (get_item(&item_val, "Recharge which item?",
(k > -1) ? k : i, (j > -1) ? j : l, 0)) {
i_ptr = &inventory[item_val];
res = TRUE;
if (i_ptr->tval == TV_ROD) {
/* now allow players to speed up recharge time of rods -CFT */
int16u t_o = i_ptr->timeout, t;
if (randint((100 - i_ptr->level + num) / 5) == 1) { /* not today... */
msg_print("The recharge backfires, and drains the rod further!");
if (t_o < 32000) /* don't overflow... */
i_ptr->timeout = (t_o + 100) * 2;
} else {
t = (int16u) (num * damroll(2, 4)); /* rechange amount */
if (t_o < t)
i_ptr->timeout = 0;
else
i_ptr->timeout = t_o - t;
}
}
/* if recharge rod... */
else { /* recharge wand/staff */
/* recharge I = recharge(20) = 1/6 failure for empty 10th level wand */
/* recharge II = recharge(60) = 1/10 failure for empty 10th level wand */
/* make it harder to recharge high level, and highly charged wands */
if (randint((num + 100 - (int)i_ptr->level - (10 * i_ptr->p1)) / 15) == 1) {
msg_print("There is a bright flash of light.");
inven_destroy(item_val);
} else {
num = (num / (i_ptr->level + 2)) + 1;
i_ptr->p1 += 2 + randint(num);
if (known2_p(i_ptr))
clear_known2(i_ptr);
clear_empty(i_ptr);
}
}
}
return (res);
}
/* Increase or decrease a creatures hit points -RAK- */
int
hp_monster(dir, y, x, dam)
int dir, y, x, dam;
{
register int i;
int flag, dist, monster;
register cave_type *c_ptr;
register monster_type *m_ptr;
register creature_type *r_ptr;
vtype out_val, m_name;
monster = FALSE;
flag = FALSE;
dist = 0;
do {
(void)mmove(dir, &y, &x);
dist++;
c_ptr = &cave[y][x];
if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
flag = TRUE;
else if (c_ptr->cptr > 1) {
flag = TRUE;
m_ptr = &m_list[c_ptr->cptr];
r_ptr = &c_list[m_ptr->mptr];
monster_name(m_name, m_ptr, r_ptr);
monster = TRUE;
i = mon_take_hit((int)c_ptr->cptr, dam, TRUE);
if (i >= 0) {
(void)sprintf(out_val, "%s dies in a fit of agony.", m_name);
msg_print(out_val);
prt_experience();
} else if (dam > 0) {
(void)sprintf(out_val,
pain_message((int)c_ptr->cptr, dam), m_name);
msg_print(out_val);
}
}
}
while (!flag);
return (monster);
}
/* Drains life; note it must be living. -RAK- */
int
drain_life(dir, y, x, dam)
int dir, y, x, dam;
{
register int i;
int flag, dist, drain;
register cave_type *c_ptr;
register monster_type *m_ptr;
register creature_type *r_ptr;
vtype out_val, m_name;
drain = FALSE;
flag = FALSE;
dist = 0;
do {
(void)mmove(dir, &y, &x);
dist++;
c_ptr = &cave[y][x];
if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
flag = TRUE;
else if (c_ptr->cptr > 1) {
flag = TRUE;
m_ptr = &m_list[c_ptr->cptr];
r_ptr = &c_list[m_ptr->mptr];
if (((r_ptr->cdefense & UNDEAD) == 0) &&
((r_ptr->cdefense & DEMON) == 0) &&
(r_ptr->cchar != 'E' && r_ptr->cchar != 'g' && r_ptr->cchar != 'v')) {
drain = TRUE;
monster_name(m_name, m_ptr, r_ptr);
i = mon_take_hit((int)c_ptr->cptr, dam, TRUE);
if (i >= 0) {
(void)sprintf(out_val, "%s dies in a fit of agony.", m_name);
msg_print(out_val);
prt_experience();
} else {
(void)sprintf(out_val,
pain_message((int)c_ptr->cptr, dam), m_name);
msg_print(out_val);
}
} else {
if (r_ptr->cdefense & UNDEAD)
c_recall[m_ptr->mptr].r_cdefense |= UNDEAD;
else
c_recall[m_ptr->mptr].r_cdefense |= DEMON;
}
}
}
while (!flag);
return (drain);
}
/* Increase or decrease a creatures speed -RAK- */
/* NOTE: cannot slow a winning creature (BALROG) */
int
speed_monster(dir, y, x, spd)
int dir, y, x, spd;
{
int flag, dist, speed;
register cave_type *c_ptr;
register monster_type *m_ptr;
register creature_type *r_ptr;
vtype out_val, m_name;
speed = FALSE;
flag = FALSE;
dist = 0;
do {
(void)mmove(dir, &y, &x);
dist++;
c_ptr = &cave[y][x];
if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
flag = TRUE;
else if (c_ptr->cptr > 1) {
flag = TRUE;
m_ptr = &m_list[c_ptr->cptr];
r_ptr = &c_list[m_ptr->mptr];
monster_name(m_name, m_ptr, r_ptr);
if (spd > 0) {
m_ptr->cspeed += spd;
m_ptr->csleep = 0;
(void)sprintf(out_val, "%s starts moving faster.", m_name);
msg_print(out_val);
speed = TRUE;
} else if ((r_ptr->level >
randint((py.misc.lev - 10) < 1 ? 1 : (py.misc.lev - 10)) + 10) ||
(r_ptr->cdefense & UNIQUE)) {
(void)sprintf(out_val, "%s is unaffected.", m_name);
msg_print(out_val);
m_ptr->csleep = 0;
} else {
m_ptr->cspeed += spd;
m_ptr->csleep = 0;
(void)sprintf(out_val, "%s starts moving slower.", m_name);
msg_print(out_val);
speed = TRUE;
}
}
}
while (!flag);
return (speed);
}
/* Confuse a creature -RAK- */
int
confuse_monster(dir, y, x, lvl)
int dir, y, x, lvl;
{
int flag, dist, confuse;
register cave_type *c_ptr;
register monster_type *m_ptr;
register creature_type *r_ptr;
vtype out_val, m_name;
confuse = FALSE;
flag = FALSE;
dist = 0;
do {
(void)mmove(dir, &y, &x);
dist++;
c_ptr = &cave[y][x];
if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
flag = TRUE;
else if (c_ptr->cptr > 1) {
m_ptr = &m_list[c_ptr->cptr];
r_ptr = &c_list[m_ptr->mptr];
monster_name(m_name, m_ptr, r_ptr);
flag = TRUE;
if ((r_ptr->level >
randint((py.misc.lev - 10) < 1 ? 1 : (py.misc.lev - 10)) + 10) ||
(r_ptr->cdefense & UNIQUE ||
r_ptr->spells2 & (BREATH_CO | BREATH_CH))) {
if (m_ptr->ml && (r_ptr->cdefense & CHARM_SLEEP))
c_recall[m_ptr->mptr].r_cdefense |= CHARM_SLEEP;
(void)sprintf(out_val, "%s is unaffected.", m_name);
msg_print(out_val);
m_ptr->csleep = 0;
} else {
if (m_ptr->confused < 230)
m_ptr->confused += (int8u) (damroll(3, (lvl / 2)) + 1);
confuse = TRUE;
m_ptr->csleep = 0;
(void)sprintf(out_val, "%s appears confused.", m_name);
msg_print(out_val);
}
}
}
while (!flag);
return (confuse);
}
/* Scare a creature -DGK */
int
fear_monster(dir, y, x, lvl)
int dir, y, x, lvl;
{
int flag, dist, fear;
register cave_type *c_ptr;
register monster_type *m_ptr;
register creature_type *r_ptr;
vtype out_val, m_name;
fear = FALSE;
flag = FALSE;
dist = 0;
do {
(void)mmove(dir, &y, &x);
dist++;
c_ptr = &cave[y][x];
if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
flag = TRUE;
else if (c_ptr->cptr > 1) {
m_ptr = &m_list[c_ptr->cptr];
r_ptr = &c_list[m_ptr->mptr];
monster_name(m_name, m_ptr, r_ptr);
flag = TRUE;
if ((r_ptr->level >
randint((py.misc.lev - 10) < 1 ? 1 : (py.misc.lev - 10)) + 10) ||
(r_ptr->cdefense & UNIQUE)) {
if (m_ptr->ml && (r_ptr->cdefense & CHARM_SLEEP))
c_recall[m_ptr->mptr].r_cdefense |= CHARM_SLEEP;
(void)sprintf(out_val, "%s is unaffected.", m_name);
msg_print(out_val);
m_ptr->csleep = 0;
} else {
if (m_ptr->monfear < 175)
m_ptr->monfear += (int8u) (damroll(3, (lvl / 2)) + 1);
fear = TRUE;
m_ptr->csleep = 0;
(void)sprintf(out_val, "%s flees in terror!", m_name);
msg_print(out_val);
}
}
}
while (!flag);
return (fear);
}
/* Sleep a creature. -RAK- */
int
sleep_monster(dir, y, x)
int dir, y, x;
{
int flag, dist, sleep;
register cave_type *c_ptr;
register monster_type *m_ptr;
register creature_type *r_ptr;
vtype out_val, m_name;
sleep = FALSE;
flag = FALSE;
dist = 0;
do {
(void)mmove(dir, &y, &x);
dist++;
c_ptr = &cave[y][x];
if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
flag = TRUE;
else if (c_ptr->cptr > 1) {
m_ptr = &m_list[c_ptr->cptr];
r_ptr = &c_list[m_ptr->mptr];
flag = TRUE;
monster_name(m_name, m_ptr, r_ptr);
if ((r_ptr->level >
randint((py.misc.lev - 10) < 1 ? 1 : (py.misc.lev - 10)) + 10) ||
(r_ptr->cdefense & UNIQUE) || (r_ptr->cdefense & CHARM_SLEEP)) {
if (m_ptr->ml && (r_ptr->cdefense & CHARM_SLEEP))
c_recall[m_ptr->mptr].r_cdefense |= CHARM_SLEEP;
(void)sprintf(out_val, "%s is unaffected.", m_name);
msg_print(out_val);
} else {
m_ptr->csleep = 500;
sleep = TRUE;
(void)sprintf(out_val, "%s falls asleep.", m_name);
msg_print(out_val);
}
}
}
while (!flag);
return (sleep);
}
/* Turn stone to mud, delete wall. -RAK- */
int
wall_to_mud(dir, y, x)
int dir, y, x;
{
int i, wall, dist;
bigvtype out_val, tmp_str;
register int flag;
register cave_type *c_ptr;
register monster_type *m_ptr;
register creature_type *r_ptr;
vtype m_name;
wall = FALSE;
flag = FALSE;
dist = 0;
do {
(void)mmove(dir, &y, &x);
dist++;
c_ptr = &cave[y][x];
/* note, this ray can move through walls as it turns them to mud */
if (dist == OBJ_BOLT_RANGE)
flag = TRUE;
if (c_ptr->fval == BOUNDARY_WALL) {
flag = TRUE;
if (test_light(y, x))
msg_print("The wall resists your spell.");
} else if ((c_ptr->fval >= MIN_CAVE_WALL)) {
flag = TRUE;
(void)twall(y, x, 1, 0);
if (test_light(y, x)) {
msg_print("The wall turns into mud.");
check_view();
wall = TRUE;
}
} else if ((c_ptr->tptr != 0) && (c_ptr->fval >= MIN_CLOSED_SPACE)) {
flag = TRUE;
if (panel_contains(y, x) && test_light(y, x)) {
objdes(tmp_str, &t_list[c_ptr->tptr], FALSE);
if ((t_list[c_ptr->tptr].tval == TV_RUBBLE) && (randint(10)==1)) {
delete_object(y,x);
place_object(y,x);
lite_spot(y,x);
(void) sprintf(out_val,
"The %s turns into mud, revealing an object!",\
tmp_str);
}
else {
(void) delete_object(y, x);
(void) sprintf(out_val, "The %s turns into mud.", tmp_str);
}
msg_print(out_val);
wall = TRUE;
}
}
if (c_ptr->cptr > 1) {
m_ptr = &m_list[c_ptr->cptr];
r_ptr = &c_list[m_ptr->mptr];
if (HURT_ROCK & r_ptr->cdefense) {
monster_name(m_name, m_ptr, r_ptr);
flag = m_ptr->ml;
i = mon_take_hit((int)c_ptr->cptr, (20 + randint(30)), TRUE);
if (flag) {
if (i >= 0) {
c_recall[i].r_cdefense |= HURT_ROCK;
(void)sprintf(out_val, "%s dissolves!", m_name);
msg_print(out_val);
prt_experience(); /* print msg before calling prt_exp */
} else {
c_recall[m_ptr->mptr].r_cdefense |= HURT_ROCK;
(void)sprintf(out_val, "%s grunts in pain!", m_name);
msg_print(out_val);
}
}
flag = TRUE;
}
}
}
while (!flag);
return (wall);
}
/* Destroy all traps and doors in a given direction -RAK- */
int
td_destroy2(dir, y, x)
int dir, y, x;
{
register int destroy2, dist;
register cave_type *c_ptr;
register inven_type *t_ptr;
destroy2 = FALSE;
dist = 0;
do {
(void)mmove(dir, &y, &x);
dist++;
c_ptr = &cave[y][x];
/* must move into first closed spot, as it might be a secret door */
if (c_ptr->tptr != 0) {
t_ptr = &t_list[c_ptr->tptr];
if (t_ptr->tval == TV_CHEST) /* let's untrap it instead -CWS */
t_ptr->flags &= ~(CH_TRAPPED | CH_LOCKED);
else if ((t_ptr->tval == TV_INVIS_TRAP) || (t_ptr->tval == TV_VIS_TRAP) ||
(t_ptr->tval == TV_OPEN_DOOR) || (t_ptr->tval == TV_CLOSED_DOOR)
|| (t_ptr->tval == TV_SECRET_DOOR)) {
if (delete_object(y, x)) {
msg_print("There is a bright flash of light!");
destroy2 = TRUE;
}
}
}
}
while ((dist <= OBJ_BOLT_RANGE) || c_ptr->fval <= MAX_OPEN_SPACE);
return (destroy2);
}
/* polymorph is now uniform for poly/mass poly/choas poly, and only
as deadly as chaos poly is. This still makes polymorphing a bad
idea, but it won't be automatically fatal. -CFT */
static int
poly(int mnum)
{
register creature_type *c_ptr = &c_list[m_list[mnum].mptr];
int y, x;
int i,j,k;
if (c_ptr->cdefense & UNIQUE) return 0;
y = m_list[mnum].fy;
x = m_list[mnum].fx;
i = (randint(20)/randint(9))+1;
k = j = c_ptr->level;
if ((j -=i)<0) j = 0;
if ((k +=i)>MAX_MONS_LEVEL) k = MAX_MONS_LEVEL;
delete_monster(mnum);
do {
i = randint(m_level[k]-m_level[j])-1+m_level[j]; /* new creature index */
} while (c_list[i].cdefense & UNIQUE);
place_monster(y,x,i,FALSE);
return 1;
}
/* polymorph now safer. not safe, just safer -CFT */
/* Polymorph a monster -RAK- */
/* NOTE: cannot polymorph a winning creature (BALROG) */
int
poly_monster(dir, y, x)
int dir, y, x;
{
int dist, flag, flag2, p;
register cave_type *c_ptr;
register creature_type *r_ptr;
register monster_type *m_ptr;
vtype out_val, m_name;
p = FALSE;
flag = FALSE;
flag2= FALSE;
dist = 0;
do {
(void) mmove(dir, &y, &x);
dist++;
c_ptr = &cave[y][x];
if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
flag = TRUE;
else if (c_ptr->cptr > 1) {
m_ptr = &m_list[c_ptr->cptr];
r_ptr = &c_list[m_ptr->mptr];
if ((r_ptr->level < randint((py.misc.lev-10)<1?1:(py.misc.lev-10))+10)
&& !(r_ptr->cdefense & UNIQUE)) {
poly(c_ptr->cptr);
if (panel_contains(y, x) && (c_ptr->tl || c_ptr->pl))
p = TRUE;
} else {
monster_name (m_name, m_ptr, r_ptr);
(void) sprintf(out_val, "%s is unaffected.", m_name);
msg_print(out_val);
}
}
}
while (!flag);
return(p);
}
/* Create a wall. -RAK- */
int
build_wall(dir, y, x)
int dir, y, x;
{
register int i;
int build, damage, dist, flag;
register cave_type *c_ptr;
register monster_type *m_ptr;
register creature_type *r_ptr;
vtype m_name, out_val;
build = FALSE;
dist = 0;
flag = FALSE;
do {
(void)mmove(dir, &y, &x);
dist++;
c_ptr = &cave[y][x];
if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
flag = TRUE;
else {
if (c_ptr->cptr > 1) {
/* stop the wall building */
flag = TRUE;
m_ptr = &m_list[c_ptr->cptr];
r_ptr = &c_list[m_ptr->mptr];
if (!(r_ptr->cmove & CM_PHASE)) {
/* monster does not move, can't escape the wall */
if (r_ptr->cmove & CM_ATTACK_ONLY)
damage = 250;
else
damage = damroll(4, 8);
monster_name(m_name, m_ptr, r_ptr);
(void)sprintf(out_val, "%s wails out in pain!", m_name);
msg_print(out_val);
i = mon_take_hit((int)c_ptr->cptr, damage, TRUE);
if (i >= 0) {
(void)sprintf(out_val, "%s is embedded in the rock.",
m_name);
msg_print(out_val);
/* prt_experience(); */
}
} else if (r_ptr->cchar == 'E' || r_ptr->cchar == 'X') {
/*
* must be an earth elemental or an earth spirit, or a Xorn
* increase its hit points
*/
m_ptr->hp += damroll(4, 8);
}
}
if (c_ptr->tptr != 0)
if (((t_list[c_ptr->tptr].tval >= TV_MIN_WEAR) &&
(t_list[c_ptr->tptr].tval <= TV_MAX_WEAR) &&
(t_list[c_ptr->tptr].flags2 & TR_ARTIFACT))
|| (t_list[c_ptr->tptr].tval == TV_UP_STAIR)
|| (t_list[c_ptr->tptr].tval == TV_DOWN_STAIR)
|| (t_list[c_ptr->tptr].tval == TV_STORE_DOOR))
continue; /* don't bury the artifact/stair/store */
else
(void)delete_object(y, x);
c_ptr->fval = MAGMA_WALL;
c_ptr->fm = FALSE;
lite_spot(y, x);
i++;
build = TRUE;
}
}
while (!flag);
return (build);
}
/* Replicate a creature -RAK- */
int
clone_monster(dir, y, x)
int dir, y, x;
{
register cave_type *c_ptr;
register int dist, flag;
dist = 0;
flag = FALSE;
do {
(void)mmove(dir, &y, &x);
dist++;
c_ptr = &cave[y][x];
if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
flag = TRUE;
else if (c_ptr->cptr > 1) {
m_list[c_ptr->cptr].csleep = 0;
/* monptr of 0 is safe here, since can't reach here from creatures */
return multiply_monster(y, x, (int)m_list[c_ptr->cptr].mptr, 0);
}
}
while (!flag);
return (FALSE);
}
/* Move the creature record to a new location -RAK- */
void
teleport_away(monptr, dis)
int monptr, dis;
{
register int yn, xn, ctr;
register monster_type *m_ptr;
m_ptr = &m_list[monptr];
ctr = 0;
do {
do {
yn = m_ptr->fy + (randint(2 * dis + 1) - (dis + 1));
xn = m_ptr->fx + (randint(2 * dis + 1) - (dis + 1));
}
while (!in_bounds(yn, xn));
ctr++;
if (ctr > 9) {
ctr = 0;
dis += 5;
}
}
while ((cave[yn][xn].fval >= MIN_CLOSED_SPACE) || (cave[yn][xn].cptr != 0));
move_rec((int)m_ptr->fy, (int)m_ptr->fx, yn, xn);
lite_spot((int)m_ptr->fy, (int)m_ptr->fx);
m_ptr->fy = yn;
m_ptr->fx = xn;
/* this is necessary, because the creature is not currently visible in its
* new position
*/
m_ptr->ml = FALSE;
m_ptr->cdis = distance(char_row, char_col, yn, xn);
update_mon(monptr);
}
/* Teleport player to spell casting creature -RAK- */
void
teleport_to(ny, nx)
int ny, nx;
{
int dis, ctr, y, x;
dis = 1;
ctr = 0;
do {
do { /* bounds check added -CFT */
y = ny + (randint(2 * dis + 1) - (dis + 1));
x = nx + (randint(2 * dis + 1) - (dis + 1));
} while (!in_bounds(y, x));
ctr++;
if (ctr > (4 * dis * dis + 4 * dis + 1)) {
ctr = 0;
dis++;
}
}
while ((cave[y][x].fval >= MIN_CLOSED_SPACE) || (cave[y][x].cptr >= 2));
move_rec(char_row, char_col, y, x);
darken_player(char_row, char_col);
char_row = y;
char_col = x;
check_view();
/* light creatures */
creatures(FALSE);
}
/* Teleport all creatures in a given direction away -RAK- */
int
teleport_monster(dir, y, x)
int dir, y, x;
{
register int flag, result, dist;
register cave_type *c_ptr;
flag = FALSE;
result = FALSE;
dist = 0;
do {
(void)mmove(dir, &y, &x);
dist++;
c_ptr = &cave[y][x];
if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
flag = TRUE;
else if (c_ptr->cptr > 1) {
m_list[c_ptr->cptr].csleep = 0; /* wake it up */
teleport_away((int)c_ptr->cptr, MAX_SIGHT * 5);
result = TRUE;
}
}
while (!flag);
return (result);
}
/* Delete all creatures within max_sight distance -RAK- */
/* NOTE : Winning creatures cannot be genocided */
int
mass_genocide(spell)
int spell;
{
register int i, result;
register monster_type *m_ptr;
register creature_type *r_ptr;
result = FALSE;
for (i = mfptr - 1; i >= MIN_MONIX; i--) {
m_ptr = &m_list[i];
r_ptr = &c_list[m_ptr->mptr];
if (((m_ptr->cdis <= MAX_SIGHT) && ((r_ptr->cmove & CM_WIN) == 0) &&
((r_ptr->cdefense & UNIQUE) == 0)) || (wizard &&
(m_ptr->cdis <= MAX_SIGHT))) {
delete_monster(i);
if (spell) {
take_hit(randint(3), "the strain of casting Mass Genocide");
prt_chp();
put_qio();
#ifdef MSDOS
delay(20* delay_spd); /* milliseconds */
#else
usleep(20000 * delay_spd); /* useconds */
#endif
}
result = TRUE;
}
}
return (result);
}
/* Delete all creatures of a given type from level. -RAK- */
/* This does not keep creatures of type from appearing later. */
/* NOTE : Winning creatures can not be genocided. */
int
genocide(spell)
int spell;
{
register int i, killed;
char typ;
register monster_type *m_ptr;
register creature_type *r_ptr;
vtype out_val;
killed = FALSE;
if (get_com("Which type of creature do you wish exterminated?", &typ))
for (i = mfptr - 1; i >= MIN_MONIX; i--) {
m_ptr = &m_list[i];
r_ptr = &c_list[m_ptr->mptr];
if ((unsigned) typ == c_list[m_ptr->mptr].cchar)
if ((r_ptr->cmove & CM_WIN) == 0) {
delete_monster(i);
if (spell) {
take_hit(randint(4), "the strain of casting Genocide");
prt_chp();
put_qio();
#ifdef MSDOS
delay(20 * delay_spd); /* milliseconds */
#else
usleep(20000 * delay_spd); /* useconds */
#endif
}
killed = TRUE;
} else {
/* genocide is a powerful spell, so we will let the player
* know the names of the creatures he did not destroy, this
* message makes no sense otherwise
*/
if (r_ptr->cdefense & UNIQUE)
(void)sprintf(out_val, "%s is unaffected.", r_ptr->name);
else
(void)sprintf(out_val, "The %s is unaffected.", r_ptr->name);
msg_print(out_val);
}
}
return (killed);
}
/* Change speed of any creature . -RAK- */
/* NOTE: cannot slow a winning creature (BALROG) */
int
speed_monsters(spd)
int spd;
{
register int i, speed;
register monster_type *m_ptr;
register creature_type *r_ptr;
vtype out_val, m_name;
speed = FALSE;
for (i = mfptr - 1; i >= MIN_MONIX; i--) {
m_ptr = &m_list[i];
r_ptr = &c_list[m_ptr->mptr];
monster_name(m_name, m_ptr, r_ptr);
if (!los(char_row, char_col, (int)m_ptr->fy, (int)m_ptr->fx))
/* do nothing */
;
else if (spd > 0) {
m_ptr->cspeed += spd;
m_ptr->csleep = 0;
if (m_ptr->ml) {
speed = TRUE;
(void)sprintf(out_val, "%s starts moving faster.", m_name);
msg_print(out_val);
}
} else if ((r_ptr->level <
randint((py.misc.lev - 10) < 1 ? 1 : (py.misc.lev - 10)) + 10) &&
!(r_ptr->cdefense & UNIQUE)) {
m_ptr->cspeed += spd;
m_ptr->csleep = 0;
if (m_ptr->ml) {
(void)sprintf(out_val, "%s starts moving slower.", m_name);
msg_print(out_val);
speed = TRUE;
}
} else if (m_ptr->ml) {
(void)sprintf(out_val, "%s is unaffected.", m_name);
msg_print(out_val);
}
}
return (speed);
}
/* Sleep any creature . -RAK- */
int
sleep_monsters2()
{
register int i, sleep;
register monster_type *m_ptr;
register creature_type *r_ptr;
vtype out_val, m_name;
sleep = FALSE;
for (i = mfptr - 1; i >= MIN_MONIX; i--) {
m_ptr = &m_list[i];
r_ptr = &c_list[m_ptr->mptr];
monster_name(m_name, m_ptr, r_ptr);
if ((m_ptr->cdis > MAX_SIGHT) ||
!los(char_row, char_col, (int)m_ptr->fy, (int)m_ptr->fx))
/* do nothing */
;
else if ((r_ptr->level >
randint((py.misc.lev - 10) < 1 ? 1 : (py.misc.lev - 10)) + 10) ||
(r_ptr->cdefense & UNIQUE) || (r_ptr->cdefense & CHARM_SLEEP)) {
if (m_ptr->ml) {
if (r_ptr->cdefense & CHARM_SLEEP)
c_recall[m_ptr->mptr].r_cdefense |= CHARM_SLEEP;
(void)sprintf(out_val, "%s is unaffected.", m_name);
msg_print(out_val);
}
} else {
m_ptr->csleep = 500;
if (m_ptr->ml) {
(void)sprintf(out_val, "%s falls asleep.", m_name);
msg_print(out_val);
sleep = TRUE;
}
}
}
return (sleep);
}
/* Polymorph any creature that player can see. -RAK- */
/* NOTE: cannot polymorph a winning creature (BALROG) */
int
mass_poly()
{
register int i;
int mass;
register monster_type *m_ptr;
register creature_type *r_ptr;
mass = FALSE;
for (i = mfptr - 1; i >= MIN_MONIX; i--) {
m_ptr = &m_list[i];
if (m_ptr->cdis <= MAX_SIGHT) {
r_ptr = &c_list[m_ptr->mptr];
if (((r_ptr->cmove & CM_WIN) == 0) && !(r_ptr->cdefense & UNIQUE)) {
mass = poly(i);
}
}
}
return(mass);
}
/* Display evil creatures on current panel -RAK- */
int
detect_evil()
{
register int i, flag;
register monster_type *m_ptr;
flag = FALSE;
for (i = mfptr - 1; i >= MIN_MONIX; i--) {
m_ptr = &m_list[i];
if (panel_contains((int)m_ptr->fy, (int)m_ptr->fx) &&
(EVIL & c_list[m_ptr->mptr].cdefense)) {
m_ptr->ml = TRUE;
/* works correctly even if hallucinating */
print((char)c_list[m_ptr->mptr].cchar, (int)m_ptr->fy,
(int)m_ptr->fx);
flag = TRUE;
}
}
if (flag) {
msg_print("You sense the presence of evil!");
msg_print(NULL);
/* must unlight every monster just lighted */
creatures(FALSE);
}
return (flag);
}
/* Change players hit points in some manner -RAK- */
int
hp_player(num)
int num;
{
register int res;
register struct misc *m_ptr;
res = FALSE;
m_ptr = &py.misc;
if (m_ptr->chp < m_ptr->mhp) {
m_ptr->chp += num;
if (m_ptr->chp > m_ptr->mhp) {
m_ptr->chp = m_ptr->mhp;
m_ptr->chp_frac = 0;
}
prt_chp();
num = num / 5;
if (num < 3) {
if (num == 0)
msg_print("You feel a little better.");
else
msg_print("You feel better.");
} else {
if (num < 7)
msg_print("You feel much better.");
else
msg_print("You feel very good.");
}
res = TRUE;
}
return (res);
}
/* Cure players confusion -RAK- */
int
cure_confusion()
{
register int cure;
register struct flags *f_ptr;
cure = FALSE;
f_ptr = &py.flags;
if (f_ptr->confused > 1) {
f_ptr->confused = 1;
cure = TRUE;
}
return (cure);
}
/* Cure players blindness -RAK- */
int
cure_blindness()
{
register int cure;
register struct flags *f_ptr;
cure = FALSE;
f_ptr = &py.flags;
if (f_ptr->blind > 1) {
f_ptr->blind = 1;
cure = TRUE;
}
return (cure);
}
/* Cure poisoning -RAK- */
int
cure_poison()
{
register int cure;
register struct flags *f_ptr;
cure = FALSE;
f_ptr = &py.flags;
if (f_ptr->poisoned > 1) {
f_ptr->poisoned = 1;
cure = TRUE;
}
return (cure);
}
/* Cure the players fear -RAK- */
int
remove_fear()
{
register int result;
register struct flags *f_ptr;
result = FALSE;
f_ptr = &py.flags;
if (f_ptr->afraid > 1) {
f_ptr->afraid = 1;
result = TRUE;
}
return (result);
}
/* This is a fun one. In a given block, pick some walls and */
/* turn them into open spots. Pick some open spots and turn */
/* them into walls. An "Earthquake" effect. -RAK- */
void
earthquake()
{
register int i, j;
register cave_type *c_ptr;
register monster_type *m_ptr;
register creature_type *r_ptr;
int kill, damage, tmp, y, x;
vtype out_val, m_name;
for (i = char_row - 10; i <= char_row + 10; i++)
for (j = char_col - 10; j <= char_col + 10; j++)
if (((i != char_row) || (j != char_col)) &&
in_bounds(i, j) && (distance(char_row, char_col, i, j)<=10) &&
(randint(8) == 1)) {
c_ptr = &cave[i][j];
if (c_ptr->tptr != 0)
if (((t_list[c_ptr->tptr].tval >= TV_MIN_WEAR) &&
(t_list[c_ptr->tptr].tval <= TV_MAX_WEAR) &&
(t_list[c_ptr->tptr].flags2 & TR_ARTIFACT))
|| (t_list[c_ptr->tptr].tval == TV_UP_STAIR)
|| (t_list[c_ptr->tptr].tval == TV_DOWN_STAIR)
|| (t_list[c_ptr->tptr].tval == TV_STORE_DOOR))
continue; /* don't touch artifacts or stairs or
* stores -CFT */
else
(void)delete_object(i, j);
if (c_ptr->cptr > 1) {
m_ptr = &m_list[c_ptr->cptr];
r_ptr = &c_list[m_ptr->mptr];
if (!(r_ptr->cmove & CM_PHASE) && !(r_ptr->cdefense & BREAK_WALL)) {
if ((movement_rate(c_ptr->cptr) == 0) ||
(r_ptr->cmove & CM_ATTACK_ONLY))
/* monster can not move to escape the wall */
kill = TRUE;
else {
/* only kill if there is nowhere for the monster to escape to */
kill = TRUE;
for (y = i - 1; y <= i + 1; y++)
for (x = j - 1; x <= j + 1; x++)
if (cave[y][x].fval >= MIN_CLOSED_SPACE)
kill = FALSE;
}
if (kill)
damage = 320;
else
damage = damroll(3 + randint(3), 8+randint(5));
monster_name(m_name, m_ptr, r_ptr);
(void)sprintf(out_val, "%s wails out in pain!", m_name);
msg_print(out_val);
i = mon_take_hit((int)c_ptr->cptr, damage, TRUE);
if (i >= 0) {
(void)sprintf(out_val, "%s is embedded in the rock.",
m_name);
msg_print(out_val);
/* prt_experience(); */
}
}
}
if ((c_ptr->fval >= MIN_CAVE_WALL) && (c_ptr->fval != BOUNDARY_WALL)) {
c_ptr->fval = CORR_FLOOR;
c_ptr->pl = FALSE;
c_ptr->fm = FALSE;
} else if (c_ptr->fval <= MAX_CAVE_FLOOR) {
tmp = randint(10);
if (tmp < 6)
c_ptr->fval = QUARTZ_WALL;
else if (tmp < 9)
c_ptr->fval = MAGMA_WALL;
else
c_ptr->fval = GRANITE_WALL;
c_ptr->fm = FALSE;
}
lite_spot(i, j);
}
}
/* Evil creatures don't like this. -RAK- */
int
protect_evil()
{
register int res;
register struct flags *f_ptr;
f_ptr = &py.flags;
if (f_ptr->protevil == 0)
res = TRUE;
else
res = FALSE;
f_ptr->protevil += randint(25) + 3 * py.misc.lev;
return (res);
}
/* Create some high quality mush for the player. -RAK- */
/* Nope, let's just fill him up and save everybody time... -CWS */
void
create_food()
{
msg_print("You feel full!");
msg_print(NULL);
#if defined(SATISFY_HUNGER) /* new create food code -CWS */
py.flags.food = PLAYER_FOOD_MAX;
#else
/* add to food timer rather than create mush - cba */
add_food(object_list[OBJ_MUSH].p1);
#endif
py.flags.status &= ~(PY_WEAK | PY_HUNGRY);
prt_hunger();
}
int
banish_creature(cflag, dist)
int32u cflag;
int dist;
{
register int i;
int dispel;
register monster_type *m_ptr;
dispel = FALSE;
for (i = mfptr - 1; i >= MIN_MONIX; i--) {
m_ptr = &m_list[i];
if ((cflag & c_list[m_ptr->mptr].cdefense) &&
(m_ptr->cdis <= MAX_SIGHT) &&
los(char_row, char_col, (int)m_ptr->fy, (int)m_ptr->fx)) {
c_recall[m_ptr->mptr].r_cdefense |= cflag;
(void)teleport_away(i, dist);
dispel = TRUE;
}
}
return (dispel);
}
int
probing()
{
register int i;
int probe;
register monster_type *m_ptr;
register creature_type *r_ptr;
register recall_type *mp;
vtype out_val, m_name;
msg_print("Probing...");
probe = FALSE;
for (i = mfptr - 1; i >= MIN_MONIX; i--) {
m_ptr = &m_list[i];
r_ptr = &c_list[m_ptr->mptr];
mp = &c_recall[m_ptr->mptr];
if ((m_ptr->cdis <= MAX_SIGHT) &&
los(char_row, char_col, (int)m_ptr->fy, (int)m_ptr->fx) &&
(m_ptr->ml)) {
if (r_ptr->cdefense & UNIQUE)
sprintf(m_name, "%s", r_ptr->name);
else
sprintf(m_name, "The %s", r_ptr->name);
sprintf(out_val, "%s has %d hit points.", m_name, m_ptr->hp);
move_cursor_relative(m_ptr->fy, m_ptr->fx);
msg_print(out_val);
/* let's make probing do good things to the monster memory -CWS */
mp->r_cdefense = r_ptr->cdefense;
mp->r_cmove = (r_ptr->cmove & ~CM_TREASURE);
probe = TRUE;
}
}
if (probe)
msg_print("That's all.");
else
msg_print("You find nothing to probe.");
move_cursor_relative(char_row, char_col);
return (probe);
}
/* Attempts to destroy a type of creature. Success depends on */
/* the creatures level VS. the player's level -RAK- */
int
dispel_creature(cflag, damage)
int cflag;
int damage;
{
register int i;
int k, dispel;
register monster_type *m_ptr;
register creature_type *r_ptr;
vtype out_val, m_name;
dispel = FALSE;
for (i = mfptr - 1; i >= MIN_MONIX; i--) {
m_ptr = &m_list[i];
if ((cflag & c_list[m_ptr->mptr].cdefense) &&
(m_ptr->cdis <= MAX_SIGHT) &&
los(char_row, char_col, (int)m_ptr->fy, (int)m_ptr->fx)) {
r_ptr = &c_list[m_ptr->mptr];
c_recall[m_ptr->mptr].r_cdefense |= cflag;
monster_name (m_name, m_ptr, r_ptr);
k = mon_take_hit(i, randint(damage), FALSE);
if (k >= 0)
(void)sprintf(out_val, "%s dissolves!", m_name);
else
(void)sprintf(out_val, "%s shudders.", m_name);
msg_print(out_val);
dispel = TRUE;
if (k >= 0)
prt_experience();
}
}
return (dispel);
}
/* Attempt to turn (confuse) undead creatures. -RAK- */
int
turn_undead()
{
register int i, turn_und;
register monster_type *m_ptr;
register creature_type *r_ptr;
vtype out_val, m_name;
turn_und = FALSE;
for (i = mfptr - 1; i >= MIN_MONIX; i--) {
m_ptr = &m_list[i];
r_ptr = &c_list[m_ptr->mptr];
if ((UNDEAD & r_ptr->cdefense)
&& (m_ptr->cdis <= MAX_SIGHT)
&& (los(char_row, char_col, (int)m_ptr->fy, (int)m_ptr->fx))) {
monster_name(m_name, m_ptr, r_ptr);
if (((py.misc.lev + 1) > r_ptr->level) ||
(randint(5) == 1)) {
if (m_ptr->ml) {
(void)sprintf(out_val, "%s runs frantically!", m_name);
msg_print(out_val);
turn_und = TRUE;
c_recall[m_ptr->mptr].r_cdefense |= UNDEAD;
}
m_ptr->monfear = randint(py.misc.lev) * 2;
} else if (m_ptr->ml) {
(void)sprintf(out_val, "%s is unaffected.", m_name);
msg_print(out_val);
}
}
}
return (turn_und);
}
/* Leave a glyph of warding. Creatures will not pass over! -RAK- */
void
warding_glyph()
{
register int i;
register cave_type *c_ptr;
c_ptr = &cave[char_row][char_col];
if (c_ptr->tptr == 0) {
i = popt();
c_ptr->tptr = i;
invcopy(&t_list[i], OBJ_SCARE_MON);
}
}
/* Lose a strength point. -RAK- */
void
lose_str()
{
if (!py.flags.sustain_str) {
(void)dec_stat(A_STR);
msg_print("You feel very weak.");
} else
msg_print("You feel weak for a moment; it passes.");
}
/* Lose an intelligence point. -RAK- */
void
lose_int()
{
if (!py.flags.sustain_int) {
(void)dec_stat(A_INT);
msg_print("You become very dizzy.");
} else
msg_print("You become dizzy for a moment; it passes.");
}
/* Lose a wisdom point. -RAK- */
void
lose_wis()
{
if (!py.flags.sustain_wis) {
(void)dec_stat(A_WIS);
msg_print("You feel very naive.");
} else
msg_print("You feel naive for a moment; it passes.");
}
/* Lose a dexterity point. -RAK- */
void
lose_dex()
{
if (!py.flags.sustain_dex) {
(void)dec_stat(A_DEX);
msg_print("You feel very sore.");
} else
msg_print("You feel sore for a moment; it passes.");
}
/* Lose a constitution point. -RAK- */
void
lose_con()
{
if (!py.flags.sustain_con) {
(void)dec_stat(A_CON);
msg_print("You feel very sick.");
} else
msg_print("You feel sick for a moment; it passes.");
}
/* Lose a charisma point. -RAK- */
void
lose_chr()
{
if (!py.flags.sustain_chr) {
(void)dec_stat(A_CHR);
msg_print("Your skin starts to itch.");
} else
msg_print("Your skin starts to itch, but feels better now.");
}
/* Lose experience -RAK- */
void
lose_exp(amount)
int32 amount;
{
register int i;
register struct misc *m_ptr;
register class_type *c_ptr;
m_ptr = &py.misc;
if (amount > m_ptr->exp)
m_ptr->exp = 0;
else
m_ptr->exp -= amount;
prt_experience();
i = 0;
while (((player_exp[i] * m_ptr->expfact / 100) <= m_ptr->exp)
&& (i < MAX_PLAYER_LEVEL))
i++;
/* increment i once more, because level 1 exp is stored in player_exp[0] */
i++;
if (i > MAX_PLAYER_LEVEL)
i = MAX_PLAYER_LEVEL;
if (m_ptr->lev != i) {
m_ptr->lev = i;
calc_hitpoints();
c_ptr = &class[m_ptr->pclass];
if (c_ptr->spell == MAGE) {
calc_spells(A_INT);
calc_mana(A_INT);
} else if (c_ptr->spell == PRIEST) {
calc_spells(A_WIS);
calc_mana(A_WIS);
}
prt_level();
prt_title();
}
}
/* Slow Poison -RAK- */
int
slow_poison()
{
register int slow;
register struct flags *f_ptr;
slow = FALSE;
f_ptr = &py.flags;
if (f_ptr->poisoned > 0) {
f_ptr->poisoned = f_ptr->poisoned / 2;
if (f_ptr->poisoned < 1)
f_ptr->poisoned = 1;
slow = TRUE;
msg_print("The effect of the poison has been reduced.");
}
return (slow);
}
/* Bless -RAK- */
void
bless(amount)
int amount;
{
py.flags.blessed += amount;
}
/* Detect Invisible for period of time -RAK- */
void
detect_inv2(amount)
int amount;
{
py.flags.detect_inv += amount;
}
static void
replace_spot(y, x, typ)
int y, x, typ;
{
register cave_type *c_ptr;
c_ptr = &cave[y][x];
switch (typ) {
case 1:
case 2:
case 3:
c_ptr->fval = CORR_FLOOR;
break;
case 4:
case 7:
case 10:
c_ptr->fval = GRANITE_WALL;
break;
case 5:
case 8:
case 11:
c_ptr->fval = MAGMA_WALL;
break;
case 6:
case 9:
case 12:
c_ptr->fval = QUARTZ_WALL;
break;
}
c_ptr->pl = FALSE;
c_ptr->fm = FALSE;
c_ptr->lr = FALSE; /* this is no longer part of a room */
if (c_ptr->tptr != 0)
(void)delete_object(y, x);
if (c_ptr->cptr > 1)
delete_monster((int)c_ptr->cptr);
}
/* The spell of destruction. -RAK- */
/* NOTE : Winning creatures that are deleted will be considered */
/* as teleporting to another level. This will NOT win the */
/* game. */
void
destroy_area(y, x)
register int y, x;
{
register int i, j, k;
msg_print("There is a searing blast of light!");
if (!py.flags.blindness_resist && !py.flags.light_resist)
py.flags.blind += 10 + randint(10);
if (dun_level > 0) {
for (i = (y - 15); i <= (y + 15); i++)
for (j = (x - 15); j <= (x + 15); j++)
if (in_bounds(i, j) && (cave[i][j].fval != BOUNDARY_WALL) &&
((cave[i][j].tptr == 0) ||
((t_list[cave[i][j].tptr].tval != TV_UP_STAIR) &&
(t_list[cave[i][j].tptr].tval != TV_DOWN_STAIR) &&
(!(t_list[cave[i][j].tptr].flags2 & TR_ARTIFACT))))) { /* DGK */
k = distance(i, j, y, x);
if (k == 0) /* player's spot... */
replace_spot(i, j, 1); /* clear player's spot...
* from um55 -CFT */
else if (k < 13)
replace_spot(i, j, randint(6));
else if (k < 16)
replace_spot(i, j, randint(9));
}
}
/* We need to redraw the screen. -DGK */
if (py.flags.blindness_resist || py.flags.light_resist) {
draw_cave();
creatures(FALSE); /* draw monsters */
}
}
/* Revamped! Now takes item pointer, number of times to try enchanting,
* and a flag of what to try enchanting. Artifacts resist enchantment
* some of the time, and successful enchantment to at least +0 might
* break a curse on the item. -CFT */
/* Enchants a plus onto an item. -RAK- */
int
enchant(inven_type *i_ptr, int n, int8u eflag)
{
register int chance, res = FALSE, i, a = i_ptr->flags2 & TR_ARTIFACT;
int table[13] = { 10, 50, 100, 200, 300, 400,
500, 700, 950, 990, 992, 995, 997 };
for(i=0; i<n; i++){
chance = 0;
if (eflag & ENCH_TOHIT) {
if (i_ptr->tohit < 1) chance = 0;
else if (i_ptr->tohit > 13) chance = 1000;
else chance = table[i_ptr->tohit-1];
if ((randint(1000)>chance) && (!a || randint(7)>3)) {
i_ptr->tohit++;
res = TRUE;
if ((i_ptr->tohit >= 0) && (randint(4)==1) && /* only when you get */
(i_ptr->flags & TR_CURSED)) { /* it above -1 -CFT */
msg_print("The curse is broken! ");
i_ptr->flags &= ~TR_CURSED;
i_ptr->ident &= ~ID_DAMD;
}
}
}
if (eflag & ENCH_TODAM) {
if (i_ptr->todam < 1) chance = 0;
else if (i_ptr->todam > 13) chance = 1000;
else chance = table[i_ptr->todam-1];
if ((randint(1000)>chance) && (!a || randint(7)>3)) {
i_ptr->todam++;
res = TRUE;
if ((i_ptr->todam >= 0) && (randint(4)==1) && /* only when you get */
(i_ptr->flags & TR_CURSED)) { /* it above -1 -CFT */
msg_print("The curse is broken! ");
i_ptr->flags &= ~TR_CURSED;
i_ptr->ident &= ~ID_DAMD;
}
}
}
if (eflag & ENCH_TOAC) {
if (i_ptr->toac < 1) chance = 0;
else if (i_ptr->toac > 13) chance = 1000;
else chance = table[i_ptr->toac-1];
if ((randint(1000)>chance) && (!a || randint(7)>3)) {
i_ptr->toac++;
res = TRUE;
if ((i_ptr->toac >= 0) && (randint(4)==1) && /* only when you get */
(i_ptr->flags & TR_CURSED)) { /* it above -1 -CFT */
msg_print("The curse is broken! ");
i_ptr->flags &= ~TR_CURSED;
i_ptr->ident &= ~ID_DAMD;
}
}
}
} /* for loop */
if (res) calc_bonuses ();
return(res);
}
const char *
pain_message(monptr, dam)
int monptr, dam;
{
register monster_type *m_ptr;
creature_type *c_ptr;
int percentage, oldhp, newhp;
if (dam == 0)
return "%s is unharmed."; /* avoid potential div by 0 */
m_ptr = &m_list[monptr];
c_ptr = &c_list[m_ptr->mptr];
#ifdef MSDOS /* more fix -CFT */
newhp = (int32) (m_ptr->hp);
oldhp = newhp + (int32) dam;
#else
newhp = m_ptr->hp;
oldhp = newhp + dam;
#endif
percentage = (newhp * 100) / oldhp;
if ((c_ptr->cchar == 'j') || /* Non-verbal creatures like molds */
(c_ptr->cchar == 'Q') || (c_ptr->cchar == 'v') ||
(c_ptr->cchar == 'm') || ((c_ptr->cchar == 'e') && stricmp(c_ptr->name,
"Beholder"))) {
if (percentage > 95)
return "%s barely notices.";
if (percentage > 75)
return "%s flinches.";
if (percentage > 50)
return "%s squelches.";
if (percentage > 35) {
if (randint(4) == 1) /* thanks to dbd@panacea.phys.utk.edu -CWS */
return "%s quivers in pain.";
else
return "%s imitates Bill Cosby in pain.";
}
if (percentage > 20)
return "%s writhes about.";
if (percentage > 10)
return "%s writhes in agony.";
return "%s jerks limply.";
} else if (c_ptr->cchar == 'C' || c_ptr->cchar == 'Z') {
if (percentage > 95)
return "%s shrugs off the attack.";
if (percentage > 75)
return "%s snarls with pain.";
if (percentage > 50)
return "%s yelps in pain.";
if (percentage > 35)
return "%s howls in pain.";
if (percentage > 20)
return "%s howls in agony.";
if (percentage > 10)
return "%s writhes in agony.";
return "%s yelps feebly.";
} else if (c_ptr->cchar == 'K' || c_ptr->cchar == 'c' || c_ptr->cchar == 'a' ||
c_ptr->cchar == 'U' || c_ptr->cchar == 'q' || c_ptr->cchar == 'R' ||
c_ptr->cchar == 'X' || c_ptr->cchar == 'b' || c_ptr->cchar == 'F' ||
c_ptr->cchar == 'J' || c_ptr->cchar == 'l' || c_ptr->cchar == 'r' ||
c_ptr->cchar == 's' || c_ptr->cchar == 'S' || c_ptr->cchar == 't') {
if (percentage > 95)
return "%s ignores the attack.";
if (percentage > 75)
return "%s grunts with pain.";
if (percentage > 50)
return "%s squeals in pain.";
if (percentage > 35)
return "%s shrieks in pain.";
if (percentage > 20)
return "%s shrieks in agony.";
if (percentage > 10)
return "%s writhes in agony.";
return "%s cries out feebly.";
} else {
if (percentage > 95)
return "%s shrugs off the attack.";
if (percentage > 75)
return "%s grunts with pain.";
if (percentage > 50)
return "%s cries out in pain.";
if (percentage > 35)
return "%s screams in pain.";
if (percentage > 20)
return "%s screams in agony.";
if (percentage > 10)
return "%s writhes in agony.";
return "%s cries out feebly.";
}
}
/* Removes curses from items in inventory -RAK- */
int
remove_curse()
{
register int i, result;
register inven_type *i_ptr;
result = FALSE;
for (i = INVEN_WIELD; i <= INVEN_OUTER; i++) {
i_ptr = &inventory[i];
if ((TR_CURSED & i_ptr->flags) &&
(i_ptr->name2 != SN_MORGUL) &&
(i_ptr->name2 != SN_CALRIS) &&
(i_ptr->name2 != SN_MORMEGIL)) {
if (!(!stricmp(object_list[i_ptr->index].name, "Power") &&
(i_ptr->tval == TV_RING))) {
i_ptr->flags &= ~TR_CURSED;
i_ptr->ident &= ~ID_DAMD; /* DGK */
i_ptr->inscrip[0] = '\0';
calc_bonuses();
result = TRUE;
}
}
}
return (result);
}
int
remove_all_curse()
{
register int i, result;
register inven_type *i_ptr;
result = FALSE;
for (i = INVEN_WIELD; i <= INVEN_OUTER; i++) {
i_ptr = &inventory[i];
if (TR_CURSED & i_ptr->flags) {
if (!(!stricmp(object_list[i_ptr->index].name, "Power") &&
(i_ptr->tval == TV_RING))) {
i_ptr->flags &= ~TR_CURSED;
i_ptr->ident &= ~ID_DAMD; /* DGK */
calc_bonuses();
i_ptr->inscrip[0] = '\0';
result = TRUE;
} else {
msg_print("The One Ring resists all attempts to remove it!");
}
}
}
return (result);
}
/* Restores any drained experience -RAK- */
int
restore_level()
{
register int restore;
register struct misc *m_ptr;
restore = FALSE;
m_ptr = &py.misc;
if (m_ptr->max_exp > m_ptr->exp) {
restore = TRUE;
msg_print("You feel your life energies returning.");
/* this while loop is not redundant, ptr_exp may reduce the exp level */
while (m_ptr->exp < m_ptr->max_exp) {
m_ptr->exp = m_ptr->max_exp;
prt_experience();
}
}
return (restore);
}
/* this fn only exists to avoid duplicating this code in the selfknowledge fn. -CFT */
static void
pause_if_screen_full(i, j)
int *i;
int j;
{
int t;
if (*i == 22) { /* is screen full? */
prt("-- more --", *i, j);
inkey();
for (t = 2; t < 23; t++)
erase_line(t, j); /* don't forget to erase extra */
prt("Your Attributes: (continued)", 1, j + 5);
*i = 2;
}
}
/* self-knowledge... idea from nethack. Useful for determining powers and
* resistences of items. It saves the screen, clears it, then starts listing
* attributes, a screenful at a time. (There are a LOT of attributes to
* list. It will probably take 2 or 3 screens for a powerful character whose
* using several artifacts...) -CFT
*/
void
self_knowledge()
{
int i, j;
int32u f = 0L, f2 = 0L;
for (i = INVEN_WIELD; i <= INVEN_LIGHT; i++) { /* get flags from items */
if (inventory[i].tval != TV_NOTHING) {
if (inventory[i].p1 < 0) /* don't adjust TR_STATS if p1 is negative -CWS */
f |= (inventory[i].flags & ~(TR_STATS | TR_SEARCH | TR_STEALTH) );
else
f |= inventory[i].flags;
f2 |= inventory[i].flags2;
}
}
save_screen();
/* map starts at 13, but I want a couple of spaces.
* This means must start by erasing map...
*/
j = 15;
for (i = 1; i < 23; i++)
erase_line(i, j - 2); /* erase a couple of spaces to left */
i = 1;
prt("Your Attributes:", i++, j + 5);
if (py.flags.blind > 0)
prt("You cannot see.", i++, j);
if (py.flags.confused > 0)
prt("You are confused.", i++, j);
if (py.flags.afraid > 0)
prt("You are terrified.", i++, j);
if (py.flags.cut > 0)
prt("You are bleeding.", i++, j);
if (py.flags.stun > 0)
prt("You are stunned and reeling.", i++, j);
if (py.flags.poisoned > 0)
prt("You are poisoned.", i++, j);
if (py.flags.image > 0)
prt("You are hallucinating.", i++, j);
if (py.flags.aggravate)
prt("You aggravate monsters.", i++, j);
if (py.flags.teleport)
prt("Your position is very uncertain.", i++, j);
if (py.flags.blessed > 0)
prt("You feel rightous.", i++, j);
if (py.flags.hero > 0)
prt("You feel heroic.", i++, j);
if (py.flags.shero > 0)
prt("You are in a battle rage.", i++, j);
if (py.flags.protevil > 0)
prt("You are protected from evil.", i++, j);
if (py.flags.shield > 0)
prt("You are protected by a mystic shield.", i++, j);
if (py.flags.invuln > 0)
prt("You are temporarily invulnerable.", i++, j);
if (py.flags.confuse_monster)
prt("Your hands are glowing dull red.", i++, j);
if (py.flags.new_spells > 0)
prt("You can learn some more spells.", i++, j);
if (py.flags.word_recall > 0)
prt("You will soon be recalled.", i++, j);
if (f & TR_STEALTH)
prt("You are magically stealthy.", i++, j);
if (f & TR_SEARCH) {
prt("You are magically perceptive.", i++, j);
pause_if_screen_full(&i, j);
}
if ((py.flags.see_infra) || (py.flags.tim_infra)) {
prt("Your eyes are sensitive to infrared light.", i++, j);
pause_if_screen_full(&i, j);
}
if ((py.flags.see_inv) || (py.flags.detect_inv)) {
prt("You can see invisible creatures.", i++, j);
pause_if_screen_full(&i, j);
}
if (py.flags.ffall) {
prt("You land gently.", i++, j);
pause_if_screen_full(&i, j);
}
if (py.flags.free_act) {
prt("You have free action.", i++, j);
pause_if_screen_full(&i, j);
}
if (py.flags.regenerate) {
prt("You regenerate quickly.", i++, j);
pause_if_screen_full(&i, j);
}
if (py.flags.slow_digest) {
prt("Your appetite is small.", i++, j);
pause_if_screen_full(&i, j);
}
if (py.flags.telepathy) {
prt("You have ESP.", i++, j);
pause_if_screen_full(&i, j);
}
if (py.flags.hold_life) {
prt("You have a firm hold on your life force.", i++, j);
pause_if_screen_full(&i, j);
}
if (py.flags.light) {
prt("You are carrying a permanent light.", i++, j);
pause_if_screen_full(&i, j);
}
if (py.flags.fear_resist) {
prt("You are completely fearless.", i++, j);
pause_if_screen_full(&i, j);
}
if (py.flags.blindness_resist) {
prt("Your eyes are resistant to blindness.", i++, j);
pause_if_screen_full(&i, j);
}
if (py.flags.fire_im) {
prt("You are completely immune to fire.", i++, j);
pause_if_screen_full(&i, j);
} else if ((py.flags.fire_resist) && (py.flags.resist_heat)) {
prt("You resist fire exceptionally well.", i++, j);
pause_if_screen_full(&i, j);
} else if ((py.flags.fire_resist) || (py.flags.resist_heat)) {
prt("You are resistant to fire.", i++, j);
pause_if_screen_full(&i, j);
}
if (py.flags.cold_im) {
prt("You are completely immune to cold.", i++, j);
pause_if_screen_full(&i, j);
} else if ((py.flags.cold_resist) && (py.flags.resist_cold)) {
prt("You resist cold exceptionally well.", i++, j);
pause_if_screen_full(&i, j);
} else if ((py.flags.cold_resist) || (py.flags.resist_cold)) {
prt("You are resistant to cold.", i++, j);
pause_if_screen_full(&i, j);
}
if (py.flags.acid_im) {
prt("You are completely immune to acid.", i++, j);
pause_if_screen_full(&i, j);
} else if ((py.flags.acid_resist) && (py.flags.resist_acid)) {
prt("You resist acid exceptionally well.", i++, j);
pause_if_screen_full(&i, j);
} else if ((py.flags.acid_resist) || (py.flags.resist_acid)) {
prt("You are resistant to acid.", i++, j);
pause_if_screen_full(&i, j);
}
if (py.flags.poison_im) {
prt("You are completely immune to poison.", i++, j);
pause_if_screen_full(&i, j);
} else if ((py.flags.poison_resist) && (py.flags.resist_poison)) {
prt("You resist poison exceptionally well.", i++, j);
pause_if_screen_full(&i, j);
} else if ((py.flags.poison_resist) || (py.flags.resist_poison)) {
prt("You are resistant to poison.", i++, j);
pause_if_screen_full(&i, j);
}
if (py.flags.light_im) {
prt("You are completely immune to lightning.", i++, j);
pause_if_screen_full(&i, j);
} else if ((py.flags.lght_resist) && (py.flags.resist_light)) {
prt("You resist lightning exceptionally well.", i++, j);
pause_if_screen_full(&i, j);
} else if ((py.flags.lght_resist) || (py.flags.resist_light)) {
prt("You are resistant to lightning.", i++, j);
pause_if_screen_full(&i, j);
}
if (py.flags.light_resist) {
prt("You are resistant to bright light.", i++, j);
pause_if_screen_full(&i, j);
}
if (py.flags.dark_resist) {
prt("You are resistant to darkness.", i++, j);
pause_if_screen_full(&i, j);
}
if (py.flags.confusion_resist) {
prt("You are resistant to confusion.", i++, j);
pause_if_screen_full(&i, j);
}
if (py.flags.sound_resist) {
prt("You are resistant to sonic attacks.", i++, j);
pause_if_screen_full(&i, j);
}
if (py.flags.disenchant_resist) {
prt("You are resistant to disenchantment.", i++, j);
pause_if_screen_full(&i, j);
}
if (py.flags.chaos_resist) {
prt("You are resistant to chaos.", i++, j);
pause_if_screen_full(&i, j);
}
if (py.flags.shards_resist) {
prt("You are resistant to blasts of shards.", i++, j);
pause_if_screen_full(&i, j);
}
if (py.flags.nexus_resist) {
prt("You are resistant to nexus attacks.", i++, j);
pause_if_screen_full(&i, j);
}
if (py.flags.nether_resist) {
prt("You are resistant to nether forces.", i++, j);
pause_if_screen_full(&i, j);
}
#if 0
/* Are these needed? The player can see this... For now, in here for
* completeness... -CFT
*/
if (f & TR_STR) {
prt("You are magically strong.", i++, j);
pause_if_screen_full(&i, j);
}
if (f & TR_INT) {
prt("You are magically intelligent.", i++, j);
pause_if_screen_full(&i, j);
}
if (f & TR_WIS) {
prt("You are magically wise.", i++, j);
pause_if_screen_full(&i, j);
}
if (f & TR_DEX) {
prt("You are magically agile.", i++, j);
pause_if_screen_full(&i, j);
}
if (f & TR_CON) {
prt("You are magically tough.", i++, j);
pause_if_screen_full(&i, j);
}
if (f & TR_CHR) {
prt("You are magically popular.", i++, j);
pause_if_screen_full(&i, j);
}
#endif
if (py.flags.sustain_str) {
prt("You will not become weaker.", i++, j);
pause_if_screen_full(&i, j);
}
if (py.flags.sustain_int) {
prt("You will not become dumber.", i++, j);
pause_if_screen_full(&i, j);
}
if (py.flags.sustain_wis) {
prt("You will not become less wise.", i++, j);
pause_if_screen_full(&i, j);
}
if (py.flags.sustain_con) {
prt("You will not become out of shape.", i++, j);
pause_if_screen_full(&i, j);
}
if (py.flags.sustain_dex) {
prt("You will not become clumsy.", i++, j);
pause_if_screen_full(&i, j);
}
if (py.flags.sustain_chr) {
prt("You will not become less popular.", i++, j);
pause_if_screen_full(&i, j);
}
if (inventory[INVEN_LEFT].flags2 & TR_ATTACK_SPD ||
inventory[INVEN_RIGHT].flags2 & TR_ATTACK_SPD) {
prt("You can strike at your foes with uncommon speed.", i++, j);
pause_if_screen_full(&i, j);
}
/* this IS a bit redundant, but it prevents flags from other items from
* affecting the weapon stats... -CFT
*/
if (inventory[INVEN_WIELD].tval != TV_NOTHING) {
f = inventory[INVEN_WIELD].flags;
f2 = inventory[INVEN_WIELD].flags2;
} else {
f = 0L;
f2 = 0L;
}
if (f & TR_CURSED) {
if (inventory[INVEN_WIELD].name2 == SN_MORGUL)
prt("Your weapon is truly foul.", i++, j);
else if (inventory[INVEN_WIELD].name2 == SN_CALRIS)
prt("Your bastard sword is wickedly accursed.", i++, j);
else if (inventory[INVEN_WIELD].name2 == SN_MORMEGIL)
prt("Your two-handed sword radiates an aura of unspeakable evil.", i++, j);
else
prt("Your weapon is accursed.", i++, j);
pause_if_screen_full(&i, j);
}
if (f & TR_TUNNEL) {
prt("Your weapon is an effective digging tool.", i++, j);
pause_if_screen_full(&i, j);
}
if (f2 & TR_BLESS_BLADE) {
prt("Your weapon has been blessed by the gods.", i++, j);
pause_if_screen_full(&i, j);
}
if (f2 & TR_ATTACK_SPD) {
prt("Your weapon strikes with uncommon speed.", i++, j);
pause_if_screen_full(&i, j);
}
if (f2 & TR_SLAY_ORC) {
prt("Your weapon is especially deadly against orcs.", i++, j);
pause_if_screen_full(&i, j);
}
if (f2 & TR_SLAY_TROLL) {
prt("Your weapon is especially deadly against trolls.", i++, j);
pause_if_screen_full(&i, j);
}
if (f2 & TR_SLAY_GIANT) {
prt("Your weapon is especially deadly against giants.", i++, j);
pause_if_screen_full(&i, j);
}
if (f & TR_SLAY_ANIMAL) {
prt("Your weapon is especially deadly against natural creatures.", i++, j);
pause_if_screen_full(&i, j);
}
if (f & TR_SLAY_X_DRAGON) {
prt("Your weapon is a great bane of dragons.", i++, j);
pause_if_screen_full(&i, j);
} else if (f & TR_SLAY_DRAGON) {
prt("Your weapon is especially deadly against dragons.", i++, j);
pause_if_screen_full(&i, j);
}
if (f2 & TR_SLAY_DEMON) {
prt("Your weapon strikes at demons with holy wrath.", i++, j);
pause_if_screen_full(&i, j);
}
if (f & TR_SLAY_UNDEAD) {
prt("Your weapon strikes at undead with holy wrath.", i++, j);
pause_if_screen_full(&i, j);
}
if (f & TR_SLAY_EVIL) {
prt("Your weapon fights against evil with holy fury.", i++, j);
pause_if_screen_full(&i, j);
}
if (f & TR_FROST_BRAND) {
prt("Your frigid weapon freezes your foes.", i++, j);
pause_if_screen_full(&i, j);
}
if (f & TR_FLAME_TONGUE) {
prt("Your flaming weapon burns your foes.", i++, j);
pause_if_screen_full(&i, j);
}
if (f2 & TR_LIGHTNING) {
prt("Your weapon electrocutes your foes.", i++, j);
pause_if_screen_full(&i, j);
}
if (f2 & TR_IMPACT)
prt("The unbelievable impact of your weapon can cause earthquakes.", i++, j);
pause_line(i);
restore_screen();
}
#define NO_RES 0
#define SOME_RES 1
#define RESIST 2
#define IMMUNE 3
#define SUSCEPT 4
#define CHANGED 5
#define CONFUSED 6
#define MORE_CONF 7
#define DAZED 8
#define MORE_DAZED 16
#define DEAD 32
/* This function will process a bolt/ball/breath spell hitting a monster.
* It checks for resistances, and reduces damage accordingly, and also
* adds in what "special effects" apply to the monsters. 'rad' is used to
* indicate the distance from "ground 0" for ball spells. For bolts, rad
* should be a 0 (this flags off some of the messages). dam is changed
* to reflect resistances and range. -CFT
*/
static void
spell_hit_monster(m_ptr, typ, dam, rad, y, x, by_player)
monster_type *m_ptr;
int typ, *dam, rad, *y, *x;
int8u by_player;
{
register creature_type *r_ptr;
int blind = (py.flags.status & PY_BLIND) ? 1 : 0;
int res; /* controls messages, using above #defines -CFT */
vtype cdesc, outval;
if (rad)
*dam /= rad; /* adjust damage for range... */
*y = m_ptr->fy; /* these only change if mon gets teleported */
*x = m_ptr->fx;
r_ptr = &c_list[m_ptr->mptr];
if (m_ptr->ml){
if (r_ptr->cdefense & UNIQUE)
sprintf(cdesc, "%s ", r_ptr->name);
else
sprintf(cdesc, "The %s ", r_ptr->name);
}
else
strcpy(cdesc, "It ");
res = NO_RES; /* assume until we know different -CFT */
switch ( typ ){ /* check for resists... */
case GF_MAGIC_MISSILE: /* pure damage, no resist possible */
break;
case GF_LIGHTNING:
if (r_ptr->cdefense & IM_LIGHTNING) {
res = RESIST;
*dam /= 9;
if (m_ptr->ml)
c_recall[m_ptr->mptr].r_cdefense |= IM_LIGHTNING;
}
break;
case GF_POISON_GAS:
if (r_ptr->cdefense & IM_POISON) {
res = RESIST;
*dam /= 9;
if (m_ptr->ml)
c_recall[m_ptr->mptr].r_cdefense |= IM_POISON;
}
break;
case GF_ACID:
if (r_ptr->cdefense & IM_ACID) {
res = RESIST;
*dam /= 9;
if (m_ptr->ml)
c_recall[m_ptr->mptr].r_cdefense |= IM_ACID;
}
break;
case GF_FROST:
if (r_ptr->cdefense & IM_FROST) {
res = RESIST;
*dam /= 9;
if (m_ptr->ml)
c_recall[m_ptr->mptr].r_cdefense |= IM_FROST;
}
break;
case GF_FIRE:
if (r_ptr->cdefense & IM_FIRE) {
res = RESIST;
*dam /= 9;
if (m_ptr->ml)
c_recall[m_ptr->mptr].r_cdefense |= IM_FIRE;
}
break;
case GF_HOLY_ORB:
if (r_ptr->cdefense & EVIL) {
*dam *= 2;
res = SUSCEPT;
if (m_ptr->ml)
c_recall[m_ptr->mptr].r_cdefense |= EVIL;
}
break;
case GF_ARROW: /* for now, no defense... maybe it should have a
chance of missing? -CFT */
break;
case GF_PLASMA: /* maybe IM_LIGHTNING (ball lightning is supposed
to be plasma) or IM_FIRE (since it's hot)? -CFT */
if (!strncmp("Plasma", r_ptr->name, 6) ||
(r_ptr->spells3 & BREATH_PL)){ /* if is a "plasma" monster,
or can breathe plasma, then
we assume it should be immune.
plasma bolts don't count, since
mage-types could have them, and
not deserve plasma-resist -CFT */
res = RESIST;
*dam *= 3; /* these 2 lines give avg dam of .33, ranging */
*dam /= (randint(6)+6); /* from .427 to .25 -CFT */
}
break;
case GF_NETHER: /* I assume nether is an evil, necromantic force,
so it doesn't hurt undead, and hurts evil less -CFT */
if (r_ptr->cdefense & UNDEAD) {
res = IMMUNE;
*dam = 0;
if (m_ptr->ml)
c_recall[m_ptr->mptr].r_cdefense |= UNDEAD;
}
else if (r_ptr->spells2 & BREATH_LD) { /* if can breath nether, should get
good resist to damage -CFT */
res = RESIST;
*dam *= 3; /* these 2 lines give avg dam of .33, ranging */
*dam /= (randint(6)+6); /* from .427 to .25 -CFT */
}
else if (r_ptr->cdefense & EVIL) {
*dam /= 2; /* evil takes *2 for holy, so /2 for this... -CFT */
res = SOME_RES;
if (m_ptr->ml)
c_recall[m_ptr->mptr].r_cdefense |= EVIL;
}
break;
case GF_WATER: /* water elementals should resist. anyone else? -CFT */
if ((r_ptr->cchar == 'E') && (r_ptr->name[0] == 'W')){
res = IMMUNE;
*dam = 0; /* water spirit, water ele, and Waldern -CFT */
}
break;
case GF_CHAOS:
if (r_ptr->spells2 & BREATH_CH){ /* assume anything that breathes
choas is chaotic enough to deserve resistance... -CFT */
res = RESIST;
*dam *= 3; /* these 2 lines give avg dam of .33, ranging */
*dam /= (randint(6)+6); /* from .427 to .25 -CFT */
}
if ((*dam <= m_ptr->hp) && /* don't bother if it's gonna die */
!(r_ptr->spells2 & BREATH_CH) &&
!(r_ptr->cdefense & UNIQUE) &&
(randint(90) > r_ptr->level)) { /* then we'll polymorph it -CFT */
res = CHANGED;
if (poly(cave[*y][*x].cptr))
*dam = 0; /* new monster was not hit by choas breath. This also
makes things easier to handle */
} /* end of choas-poly. If was poly-ed don't bother confuse... it's
too hectic to keep track of... -CFT */
else if (!(r_ptr->cdefense & CHARM_SLEEP) &&
!(r_ptr->spells2 & BREATH_CH) && /* choatics hard to confuse */
!(r_ptr->spells2 & BREATH_CO)){ /* so are bronze dragons */
if (m_ptr->confused > 0) {
res = MORE_CONF;
if (m_ptr->confused < 240){ /* make sure not to overflow -CFT */
m_ptr->confused += 7/(rad>0 ? rad : 1);
}
}
else {
res = CONFUSED;
m_ptr->confused = (randint(11)+5)/(rad>0 ? rad : 1);
}
}
break;
case GF_SHARDS:
if (r_ptr->spells2 & BREATH_SH){ /* shard breathers resist -CFT */
res = RESIST;
*dam *= 3; /* these 2 lines give avg dam of .33, ranging */
*dam /= (randint(6)+6); /* from .427 to .25 -CFT */
}
break;
case GF_SOUND:
if (r_ptr->spells2 & BREATH_SD){ /* ditto for sound -CFT */
res = RESIST;
*dam *= 2;
*dam /= (randint(6)+6);
}
if ((*dam <= m_ptr->hp) && /* don't bother if it's dead */
!(r_ptr->spells2 & BREATH_SD) &&
!(r_ptr->spells3 & BREATH_WA)) { /* sound and impact breathers
should not stun -CFT */
if (m_ptr->confused > 0) {
res = MORE_DAZED;
if (m_ptr->confused < 220){ /* make sure not to overflow -CFT */
m_ptr->confused += (randint(5)*2)/(rad>0 ? rad : 1);
}
}
else {
res = DAZED;
m_ptr->confused = (randint(15)+10)/(rad>0 ? rad : 1);
}
}
break;
case GF_CONFUSION:
if (r_ptr->spells2 & BREATH_CO){
res = RESIST;
*dam *= 2;
*dam /= (randint(6)+6);
}
else if (r_ptr->cdefense & CHARM_SLEEP){
res = SOME_RES;
*dam /= 2; /* only some resist, but they also avoid confuse -CFT */
}
if ((*dam <= m_ptr->hp) && /* don't bother if it's dead */
!(r_ptr->cdefense & CHARM_SLEEP) &&
!(r_ptr->spells2 & BREATH_CH) && /* choatics hard to confuse */
!(r_ptr->spells2 & BREATH_CO)) { /* so are bronze dragons */
if (m_ptr->confused > 0) {
res = MORE_CONF;
if (m_ptr->confused < 240){ /* make sure not to overflow -CFT */
m_ptr->confused += 7/(rad>0 ? rad : 1);
}
}
else {
res = CONFUSED;
m_ptr->confused = (randint(11)+5)/(rad>0 ? rad : 1);
}
}
break;
case GF_DISENCHANT:
if ((r_ptr->spells2 & BREATH_DI) ||
!strncmp("Disen", r_ptr->name, 5)) {
res = RESIST;
*dam *= 3; /* these 2 lines give avg dam of .33, ranging */
*dam /= (randint(6)+6); /* from .427 to .25 -CFT */
}
break;
case GF_NEXUS:
if ((r_ptr->spells2 & BREATH_NE) ||
!strncmp("Nexus", r_ptr->name, 5)) {
res = RESIST;
*dam *= 3; /* these 2 lines give avg dam of .33, ranging */
*dam /= (randint(6)+6); /* from .427 to .25 -CFT */
}
break;
case GF_FORCE:
if (r_ptr->spells3 & BREATH_WA){ /* breath ele force resists
ele force -CFT */
res = RESIST;
*dam *= 3; /* these 2 lines give avg dam of .33, ranging */
*dam /= (randint(6)+6); /* from .427 to .25 -CFT */
}
if ((*dam <= m_ptr->hp) &&
!(r_ptr->spells2 & BREATH_SD) &&
!(r_ptr->spells3 & BREATH_WA)){ /* sound and impact breathers
should not stun -CFT */
if (m_ptr->confused > 0) {
res = MORE_DAZED;
if (m_ptr->confused < 220){ /* make sure not to overflow -CFT */
m_ptr->confused += (randint(5)+1)/(rad>0 ? rad : 1);
}
}
else {
res = DAZED;
m_ptr->confused = randint(15)/(rad>0 ? rad : 1);
}
}
break;
case GF_INERTIA:
if (r_ptr->spells3 & BREATH_SL){ /* if can breath inertia, then
resist it. */
res = RESIST;
*dam *= 3; /* these 2 lines give avg dam of .33, ranging */
*dam /= (randint(6)+6); /* from .427 to .25 -CFT */
}
break;
case GF_LIGHT:
if (r_ptr->spells3 & BREATH_LT){ /* breathe light to res light */
res = RESIST;
*dam *= 2;
*dam /= (randint(6)+6);
}
else if (r_ptr->cdefense & HURT_LIGHT){
res = SUSCEPT;
*dam *= 2; /* hurt bad by light */
}
else if (r_ptr->spells3 & BREATH_DA){ /* breathe dark gets hurt */
res = SUSCEPT;
*dam = (*dam * 3)/2;
}
break;
case GF_DARK:
if (r_ptr->spells2 & BREATH_DA){ /* shard breathers resist -CFT */
res = RESIST;
*dam *= 2;
*dam /= (randint(6)+6);
}
else if (r_ptr->cdefense & HURT_LIGHT){
res = SOME_RES;
*dam /= 2; /* hurt bad by light, so not hurt bad by dark */
}
else if (r_ptr->spells3 & BREATH_LT){ /* breathe light gets hurt */
res = SUSCEPT;
*dam = (*dam * 3)/2;
}
break;
case GF_TIME:
if (r_ptr->spells3 & BREATH_TI){ /* time breathers resist -CFT */
res = RESIST;
*dam *= 3; /* these 2 lines give avg dam of .33, ranging */
*dam /= (randint(6)+6); /* from .427 to .25 -CFT */
}
break;
case GF_GRAVITY:
if (r_ptr->spells3 & BREATH_GR){ /* breathers resist -CFT */
res = RESIST;
*dam *= 3; /* these 2 lines give avg dam of .33, ranging */
*dam /= (randint(6)+6); /* from .427 to .25 -CFT */
}
else {
if (*dam <= m_ptr->hp) {
teleport_away(cave[m_ptr->fy][m_ptr->fx].cptr, 5);
*y = m_ptr->fy; /* teleported, so let outside world know monster moved! */
*x = m_ptr->fx;
}
}
break;
case GF_MANA: /* raw blast of power. no way to resist, is there? */
break;
case GF_METEOR: /* GF_METEOR is basically a powerful magic-missile
ball spell. I only made it a different type
so I could make it a different color -CFT */
break;
case GF_ICE: /* ice is basically frost + cuts + stun -CFT */
if (r_ptr->cdefense & IM_FROST) {
res = RESIST;
*dam /= 9;
if (m_ptr->ml)
c_recall[m_ptr->mptr].r_cdefense |= IM_FROST;
}
if ((*dam <= m_ptr->hp) &&
!(r_ptr->spells2 & BREATH_SD) &&
!(r_ptr->spells3 & BREATH_WA)){ /* sound and impact breathers
should not stun -CFT */
if (m_ptr->confused > 0) {
res += MORE_DAZED;
if (m_ptr->confused < 220){ /* make sure not to overflow -CFT */
m_ptr->confused += (randint(5)+1)/(rad>0 ? rad : 1);
}
}
else {
res += DAZED;
m_ptr->confused = randint(15)/(rad>0 ? rad : 1);
}
}
break;
default:
msg_print("Unknown typ in spell_hit_monster. This may mean trouble.");
} /* end switch for saving throws and extra effects */
if (res == CHANGED)
sprintf(outval, "%schanges!",cdesc);
else if ((*dam > m_ptr->hp) &&
(by_player || !(c_list[m_ptr->mptr].cdefense & UNIQUE))) {
res = DEAD;
if ((c_list[m_ptr->mptr].cdefense & (DEMON|UNDEAD|MINDLESS)) ||
(c_list[m_ptr->mptr].cchar == 'E') ||
(c_list[m_ptr->mptr].cchar == 'v') ||
(c_list[m_ptr->mptr].cchar == 'g') ||
(c_list[m_ptr->mptr].cchar == 'X'))
sprintf(outval, "%sis destroyed.", cdesc);
else
sprintf(outval, "%sdies.", cdesc);
}
else switch (res) {
case NO_RES:
sprintf(outval, "%sis hit.",cdesc);
break;
case SOME_RES:
sprintf(outval, "%sresists somewhat.",cdesc);
break;
case RESIST:
sprintf(outval, "%sresists.",cdesc);
break;
case IMMUNE:
sprintf(outval, "%sis immune.",cdesc);
break;
case SUSCEPT:
sprintf(outval, "%sis hit hard.",cdesc);
break;
case CONFUSED:
sprintf(outval, "%sis confused.",cdesc);
break;
case MORE_CONF:
sprintf(outval, "%sis more confused.",cdesc);
break;
case DAZED:
sprintf(outval, "%sis dazed.",cdesc);
break;
case MORE_DAZED:
sprintf(outval, "%sis more dazed.",cdesc);
break;
case (DAZED+RESIST):
sprintf(outval, "%sresists, but is dazed anyway.",cdesc);
break;
case (MORE_DAZED+RESIST):
sprintf(outval, "%sresists, but still is more dazed.",cdesc);
break;
default:
sprintf(outval,"%sis affected in a mysterious way.",cdesc);
}
if (rad || (res != NO_RES)) { /* don't show normal hit msgs for bolts -CFT */
if (!blind)
msg_print(outval);
}
}
/* This fn provides the ability to have a spell blast a line of creatures
for damage. It should look pretty neat, too... -CFT */
void
line_spell(typ, dir, y, x, dam)
int typ, dir, y, x, dam;
{
int ny,nx, dis = 0, flag = FALSE;
int t, tdam;
monster_type *m_ptr;
cave_type *c_ptr;
int8u path[OBJ_BOLT_RANGE+5][3]; /* pre calculate "flight" path, makes bolt
calc faster because fns more likely to be in mem.
Also allows redraw at reasonable spd -CFT */
path[0][0] = y; path[0][1] = x; /* orig point */
do {
(void)mmove(dir, &y, &x);
dis++;
path[dis][0] = y; path[dis][1] = x;
if ((dis>OBJ_BOLT_RANGE) || (cave[y][x].fval >= MIN_CLOSED_SPACE))
flag = TRUE;
} while (!flag);
flag = FALSE;
dis = 0;
do {
dis++;
y = path[dis][0]; x = path[dis][1];
c_ptr = &cave[y][x];
if ((dis > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
flag = TRUE; /* then stop */
else {
if (c_ptr->cptr > 1) { /* hit a monster! */
tdam = dam;
m_ptr = &m_list[c_ptr->cptr];
if (!(py.flags.status & PY_BLIND) && panel_contains(y,x)){
/* temp light monster to show it... */
t = c_ptr->pl;
c_ptr->pl = TRUE;
update_mon((int)c_ptr->cptr);
c_ptr->pl = t;
put_qio(); /* draw monster */
}
/* check resists */
spell_hit_monster(m_ptr, typ, &tdam, 1, &ny, &nx, TRUE);
c_ptr = &cave[ny][nx]; /* may be new loc if tele by grav warp */
(void) mon_take_hit((int)c_ptr->cptr, tdam, TRUE); /* hurt it */
}
if (!(py.flags.status & PY_BLIND)) {
for(t=1;t<=dis;t++)
if (panel_contains(path[t][0],path[t][1])){
#ifdef TC_COLOR
if (!no_color_flag) textcolor(bolt_color(typ));
#endif
print(bolt_char(path[t][0],path[t][1],path[t-1][0], path[t-1][1]),
path[t][0], path[t][1]);
#ifdef TC_COLOR
if (!no_color_flag) textcolor(LIGHTGRAY);
#endif
}
put_qio(); /* show line */
#ifdef MSDOS
delay(8 * delay_spd);
#else
usleep(8000 * delay_spd);
#endif
} /* if !blind */
} /* if hit monster */
} while (!flag); /* end of effects loop */
if (!(py.flags.status & PY_BLIND)) { /* now erase it -CFT */
for(t=1;t<=dis;t++){ /* erase piece-by-piece... */
lite_spot(path[t][0], path[t][1]);
for(tdam=t+1;tdam<dis;tdam++){
if (panel_contains(path[tdam][0], path[tdam][1])){
#ifdef TC_COLOR
if (!no_color_flag) textcolor(bolt_color(typ));
#endif
print(bolt_char(path[tdam][0],path[tdam][1],path[tdam-1][0],
path[tdam-1][1]), path[tdam][0], path[tdam][1]);
#ifdef TC_COLOR
if (!no_color_flag) textcolor(LIGHTGRAY);
#endif
}
}
put_qio();
#ifdef MSDOS
delay(8 * delay_spd);
#else
usleep(8000 * delay_spd);
#endif
} /* for each piece */
} /* if !blind */
}